From 1a60ae0275808108ef655ff01b5ed265fe0ccd0d Mon Sep 17 00:00:00 2001 From: Craig Treasure Date: Tue, 23 Feb 2021 13:53:09 -0800 Subject: [PATCH] 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) --- eng/.docsettings.yml | 1 + .../CHANGELOG.md | 5 + .../LICENSE.txt | 21 ++ .../MANIFEST.in | 6 + .../README.md | 199 ++++++++++++++++++ .../azure/__init__.py | 7 + .../azure/mixedreality/__init__.py | 7 + .../mixedreality/authentication/__init__.py | 11 + .../mixedreality/authentication/_client.py | 113 ++++++++++ .../authentication/_generated/__init__.py | 16 ++ .../_generated/_configuration.py | 51 +++++ .../_mixed_reality_sts_rest_client.py | 57 +++++ .../authentication/_generated/aio/__init__.py | 10 + .../_generated/aio/_configuration.py | 45 ++++ .../aio/_mixed_reality_sts_rest_client.py | 49 +++++ .../_generated/aio/operations/__init__.py | 13 ++ ...ixed_reality_sts_rest_client_operations.py | 89 ++++++++ .../_generated/models/__init__.py | 19 ++ .../_generated/models/_models.py | 54 +++++ .../_generated/models/_models_py3.py | 60 ++++++ .../_generated/operations/__init__.py | 13 ++ ...ixed_reality_sts_rest_client_operations.py | 94 +++++++++ .../authentication/_generated/py.typed | 1 + .../authentication/_shared/__init__.py | 5 + .../authentication/_shared/aio/__init__.py | 5 + .../aio/mixed_reality_token_credential.py | 67 ++++++ .../mixedreality_account_key_credential.py | 54 +++++ .../aio/static_access_token_credential.py | 38 ++++ .../_shared/authentication_endpoint.py | 9 + .../_shared/mixed_reality_token_credential.py | 50 +++++ .../mixedreality_account_key_credential.py | 46 ++++ .../_shared/static_access_token_credential.py | 27 +++ .../mixedreality/authentication/_utils.py | 73 +++++++ .../mixedreality/authentication/_version.py | 10 + .../authentication/aio/__init__.py | 11 + .../authentication/aio/_client_async.py | 112 ++++++++++ .../dev_requirements.txt | 4 + .../samples/client_sample async.py | 70 ++++++ .../samples/client_sample.py | 63 ++++++ .../sdk_packaging.toml | 7 + .../setup.cfg | 2 + .../setup.py | 80 +++++++ .../swagger/SWAGGER.md | 30 +++ .../swagger/update.ps1 | 6 + .../tests/_constants.py | 10 + .../tests/conftest.py | 11 + .../test_client.test_get_token.yaml | 38 ++++ .../test_client_async.test_get_token.yaml | 28 +++ .../tests/test_client.py | 106 ++++++++++ .../tests/test_client_async.py | 108 ++++++++++ .../test_mixed_reality_token_credential.py | 37 ++++ ...st_mixed_reality_token_credential_async.py | 37 ++++ .../test_static_access_token_credential.py | 21 ++ ...st_static_access_token_credential_async.py | 23 ++ .../tests/test_utils.py | 60 ++++++ .../azure-mixedreality-nspkg/CHANGELOG.md | 5 + .../azure-mixedreality-nspkg/MANIFEST.in | 3 + .../azure-mixedreality-nspkg/README.md | 11 + .../azure/__init__.py | 1 + .../azure/mixedreality/__init__.py | 0 .../azure-mixedreality-nspkg/setup.cfg | 2 + .../azure-mixedreality-nspkg/setup.py | 41 ++++ sdk/mixedreality/ci.yml | 4 + sdk/mixedreality/test-resources.json | 141 +++++++++++++ sdk/mixedreality/tests.yml | 13 ++ shared_requirements.txt | 1 + 66 files changed, 2411 insertions(+) create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/CHANGELOG.md create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/LICENSE.txt create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/MANIFEST.in create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/README.md create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_client.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_configuration.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_mixed_reality_sts_rest_client.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_configuration.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_mixed_reality_sts_rest_client.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/_mixed_reality_sts_rest_client_operations.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models_py3.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/_mixed_reality_sts_rest_client_operations.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/py.typed create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixed_reality_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixedreality_account_key_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/static_access_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/authentication_endpoint.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixed_reality_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixedreality_account_key_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/static_access_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_utils.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_version.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/_client_async.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/dev_requirements.txt create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample async.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/sdk_packaging.toml create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/setup.cfg create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/setup.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/swagger/SWAGGER.md create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/swagger/update.ps1 create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/_constants.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/conftest.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client.test_get_token.yaml create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client_async.test_get_token.yaml create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_client.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_client_async.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential_async.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential_async.py create mode 100644 sdk/mixedreality/azure-mixedreality-authentication/tests/test_utils.py create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/CHANGELOG.md create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/MANIFEST.in create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/README.md create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/azure/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/azure/mixedreality/__init__.py create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/setup.cfg create mode 100644 sdk/mixedreality/azure-mixedreality-nspkg/setup.py create mode 100644 sdk/mixedreality/test-resources.json create mode 100644 sdk/mixedreality/tests.yml diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index a732c246e727..d0dba16dd0bb 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -124,6 +124,7 @@ known_content_issues: - ['sdk/core/azure-mgmt-nspkg/README.rst', 'nspkg and common'] - ['sdk/core/azure-nspkg/README.rst', 'nspkg and common'] - ['sdk/keyvault/azure-keyvault-nspkg/README.md', 'nspkg and common'] + - ['sdk/mixedreality/azure-mixedreality-nspkg/README.md', 'nspkg and common'] - ['sdk/search/azure-search-nspkg/README.md', 'nspkg and common'] - ['sdk/storage/azure-storage-blob/samples/README.md', 'nspkg and common'] - ['sdk/storage/azure-storage-file-datalake/samples/README.md', 'nspkg and common'] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/CHANGELOG.md b/sdk/mixedreality/azure-mixedreality-authentication/CHANGELOG.md new file mode 100644 index 000000000000..11533387e830 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History + +## 1.0.0b1 (Unreleased) + +- Initial release. diff --git a/sdk/mixedreality/azure-mixedreality-authentication/LICENSE.txt b/sdk/mixedreality/azure-mixedreality-authentication/LICENSE.txt new file mode 100644 index 000000000000..0313a903d76c --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-authentication/MANIFEST.in b/sdk/mixedreality/azure-mixedreality-authentication/MANIFEST.in new file mode 100644 index 000000000000..b69eaab9edd0 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/MANIFEST.in @@ -0,0 +1,6 @@ +include *.md +include azure/__init__.py +include azure/mixedreality/__init__.py +include LICENSE.txt +recursive-include tests *.py +recursive-include samples *.py *.md \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-authentication/README.md b/sdk/mixedreality/azure-mixedreality-authentication/README.md new file mode 100644 index 000000000000..ca0845d344a6 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/README.md @@ -0,0 +1,199 @@ +[![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) + +# Azure Mixed Reality Authentication Package client library for Python + +Mixed Reality services, like Azure Spatial Anchors, Azure Remote Rendering, and others, use the Mixed Reality security +token service (STS) for authentication. This package supports exchanging Mixed Reality account credentials for an access +token from the STS that can be used to access Mixed Reality services. + +![Mixed Reality service authentication diagram](https://docs.microsoft.com/azure/spatial-anchors/concepts/media/spatial-anchors-authentication-overview.png) + +# Getting started + +## Currently supported environments + +This package has been tested with Python 2.7, 3.5, 3.6, 3.7, 3.8, and 3.9. + +## Prerequisites + +- An [Azure subscription][azure_sub]. +- You must have an account with an [Azure Mixed Reality service](https://azure.microsoft.com/topic/mixed-reality/): + - [Azure Remote Rendering](https://docs.microsoft.com/azure/remote-rendering/) + - [Azure Spatial Anchors](https://docs.microsoft.com/azure/spatial-anchors/) +- Familiarity with the authentication and credential concepts from the [Azure Identity library][azure_identity]. +- Python 2.7, or 3.5 or later is required to use this package. + +## Install the package + +Install the Azure Mixed Reality Authentication SDK. + +```bash +pip install --pre azure-mixedreality-authentication +``` + +## Create and authenticate a `MixedRealityStsClient` + +To create a client object to request an access token for a Mixed Reality service, you will need the `account identifier` +and `account domain` of your Mixed Reality service resource and a `credential`. + +Mixed Reality services support a few different forms of authentication: + +- Account Key authentication + - Account keys enable you to get started quickly with using Mixed Reality services. But before you deploy your application + to production, we recommend that you update your app to use Azure AD authentication. +- Azure Active Directory (AD) token authentication + - If you're building an enterprise application and your company is using Azure AD as its identity system, you can use + user-based Azure AD authentication in your app. You then grant access to your Mixed Reality accounts by using your + existing Azure AD security groups. You can also grant access directly to users in your organization. + - Otherwise, we recommend that you obtain Azure AD tokens from a web service that supports your app. We recommend this + method for production applications because it allows you to avoid embedding the credentials for access to a Mixed + Reality service in your client application. + +See [here][register_aad_app] for detailed instructions and information. + +### Using account key authentication + +Use the [Azure Portal][azure_portal] to browse to your Mixed Reality service resource and retrieve an `account key`. + +Once you have an account key, you can use the `AzureKeyCredential` class to authenticate the client as follows: + +```python +from azure.core.credentials import AzureKeyCredential +from azure.mixedreality.authentication import MixedRealityStsClient + +account_id = "" +account_domain = "" +account_key = "" +key_credential = AzureKeyCredential(account_key) + +client = MixedRealityStsClient(account_id, account_domain, key_credential) +``` + +> Note: Account key authentication is **not recommended** for production applications. + +### Using an Azure Active Directory Credential + +Account key authentication is used in most of the examples, but you can also authenticate with Azure Active Directory +using the [Azure Identity library][azure_identity]. This is the recommended method for production applications. To use +the [DefaultAzureCredential][defaultazurecredential] provider shown below, or other credential providers provided with +the Azure SDK, please install the `@azure/identity` package: + +You will also need to [register a new AAD application][register_aad_app] and grant access to your Mixed Reality resource +by assigning the appropriate role for your Mixed Reality service to your service principal. + +```python +from azure.identity import DefaultAzureCredential +from azure.mixedreality.authentication import MixedRealityStsClient + +account_id = "" +account_domain = "" +default_credential = DefaultAzureCredential() + +client = MixedRealityStsClient(account_id, account_domain, default_credential) +``` + +# Key concepts + +## MixedRealityStsClient + +The `MixedRealityStsClient` is the client library used to access the Mixed Reality STS to get an access token. An access +token can be retrieved by calling `get_token()` on an `MixedRealityStsClient` instance. + +Tokens obtained from the Mixed Reality STS have a lifetime of **24 hours**. + +### Token result value + +The return value for a successful call to `get_token` is an `azure.core.credentials.AccessToken`. + +See the authentication examples [above](#authenticate-the-client) or [Azure Identity][azure_identity] for more complex +authentication scenarios. + +## Retrieve an access token synchronously + +```python +from azure.core.credentials import AzureKeyCredential +from azure.mixedreality.authentication import MixedRealityStsClient + +account_id = "" +account_domain = "" +account_key = "" +key_credential = AzureKeyCredential(account_key) + +client = MixedRealityStsClient(account_id, account_domain, key_credential) + +token = client.get_token() +``` + +## Retrieve an access token asynchronously + +```python +from azure.core.credentials import AzureKeyCredential +from azure.mixedreality.authentication.aio import MixedRealityStsClient + +account_id = "" +account_domain = "" +account_key = "" +key_credential = AzureKeyCredential(account_key) + +client = MixedRealityStsClient(account_id, account_domain, key_credential) + +token = await client.get_token() +``` + +# Examples + +These are code samples that show common scenario operations with the Azure Mixed Reality Authentication client library. +The async versions of the samples (the python sample files appended with `_async`) show asynchronous operations, +and require Python 3.5 or later. +Before running the sample code, refer to Prerequisites + +to create a resource, then set some Environment Variables + +```bash +set MIXEDREALITY_ACCOUNT_DOMAIN="" +set MIXEDREALITY_ACCOUNT_ID="" +set MIXEDREALITY_ACCOUNT_KEY="" + +pip install azure-mixedreality-authentication + +python samples\client_sample.py +python samples\client_sample_async.py +``` + +# Troubleshooting + +The [troubleshooting](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#troubleshooting) +section for Azure Identity can be helpful when troubleshooting authentication issues. + +# Next steps + +## Mixed Reality client libraries + +- Coming soon + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +If you'd like to contribute to this library, please read the +[contributing guide](https://github.com/Azure/azure-sdk-for-python/blob/master/CONTRIBUTING.md) to learn more about how to +build and test the code. + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-python%2Fsdk%2Ftemplate%2Fazure-template%2FREADME.png) + +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[azure_portal]: https://portal.azure.com +[azure_identity]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity +[register_aad_app]: https://docs.microsoft.com/azure/spatial-anchors/concepts/authentication +[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/identity/azure-identity#defaultazurecredential diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/__init__.py new file mode 100644 index 000000000000..431ed648086a --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/__init__.py @@ -0,0 +1,7 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/__init__.py new file mode 100644 index 000000000000..431ed648086a --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/__init__.py @@ -0,0 +1,7 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/__init__.py new file mode 100644 index 000000000000..2996cdaaeb4c --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/__init__.py @@ -0,0 +1,11 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from ._version import VERSION +from ._client import MixedRealityStsClient + +__version__ = VERSION +__all__ = ['MixedRealityStsClient'] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_client.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_client.py new file mode 100644 index 000000000000..919a99cb55a1 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_client.py @@ -0,0 +1,113 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse # type: ignore + +from azure.core.credentials import AzureKeyCredential +from azure.core.tracing.decorator import distributed_trace +from azure.core.pipeline.policies import BearerTokenCredentialPolicy + +from ._generated import MixedRealityStsRestClient +from ._generated.models import TokenRequestOptions +from ._version import SDK_MONIKER +from ._shared.authentication_endpoint import construct_endpoint_url +from ._shared.mixedreality_account_key_credential import MixedRealityAccountKeyCredential +from ._utils import convert_to_access_token, generate_cv_base + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Union + from azure.core.credentials import TokenCredential + from azure.core.credentials import AccessToken + + +class MixedRealityStsClient(object): + """ A client to interact with the Mixed Reality STS service. + + :param str account_id: + The Mixed Reality service account identifier. + :param str account_domain: + The Mixed Reality service account domain. + :param Union[TokenCredential, AzureKeyCredential] credential: + The credential used to access the Mixed Reality service. + :keyword str custom_endpoint_url: + Override the Mixed Reality STS service endpoint. + """ + + def __init__(self, account_id, account_domain, credential, **kwargs): + # type: (str, str, Union[TokenCredential, AzureKeyCredential], Any) -> None + if not account_id: + raise ValueError("account_id must be a non-empty string.") + + if not account_domain: + raise ValueError("account_domain must be a non-empty string.") + + if not credential: + raise ValueError("credential can not be None.") + + self._account_id = account_id + self._account_domain = account_domain + + if isinstance(credential, AzureKeyCredential): + credential = MixedRealityAccountKeyCredential(account_id, credential) + + self._credential = credential + + endpoint_url = kwargs.pop('custom_endpoint_url', construct_endpoint_url(account_domain)) + + try: + if not endpoint_url.lower().startswith('http'): + endpoint_url = "https://" + endpoint_url + except AttributeError: + raise ValueError("Host URL must be a string.") + + parsed_url = urlparse(endpoint_url.rstrip('/')) + if not parsed_url.netloc: + raise ValueError("Invalid URL: {}".format(endpoint_url)) + + self._endpoint_url = endpoint_url + + authentication_policy = BearerTokenCredentialPolicy(credential, endpoint_url + '/.default') + + self._client = MixedRealityStsRestClient( + base_url=endpoint_url, + authentication_policy=authentication_policy, + sdk_moniker=SDK_MONIKER, + **kwargs) + + @distributed_trace + def get_token(self, **kwargs): + # type: (Any) -> AccessToken + """ + Retrieve a token from the STS service for the specified account identifier asynchronously. + :return: Instance of azure.core.credentials.AccessToken - token and expiry date of it + :rtype: ~azure.core.credentials.AccessToken + """ + token_request_options = TokenRequestOptions() + token_request_options.client_request_id = generate_cv_base() + + response = self._client.get_token( + self._account_id, + token_request_options=token_request_options, + **kwargs) + return convert_to_access_token(response) + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> MixedRealityStsClient + self._client.__enter__() # pylint:disable=no-member + return self + + def __exit__(self, *args): + # type: (*Any) -> None + self._client.__exit__(*args) # pylint:disable=no-member diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/__init__.py new file mode 100644 index 000000000000..86838c6b621e --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/__init__.py @@ -0,0 +1,16 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._mixed_reality_sts_rest_client import MixedRealityStsRestClient +__all__ = ['MixedRealityStsRestClient'] + +try: + from ._patch import patch_sdk # type: ignore + patch_sdk() +except ImportError: + pass diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_configuration.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_configuration.py new file mode 100644 index 000000000000..9a762cc1fa5c --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_configuration.py @@ -0,0 +1,51 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + +VERSION = "unknown" + +class MixedRealityStsRestClientConfiguration(Configuration): + """Configuration for MixedRealityStsRestClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + """ + + def __init__( + self, + **kwargs # type: Any + ): + # type: (...) -> None + super(MixedRealityStsRestClientConfiguration, self).__init__(**kwargs) + + kwargs.setdefault('sdk_moniker', 'mixedrealitystsrestclient/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs # type: Any + ): + # type: (...) -> None + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.RetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.RedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_mixed_reality_sts_rest_client.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_mixed_reality_sts_rest_client.py new file mode 100644 index 000000000000..53973ea0933f --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/_mixed_reality_sts_rest_client.py @@ -0,0 +1,57 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING + +from azure.core import PipelineClient +from msrest import Deserializer, Serializer + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Optional + +from ._configuration import MixedRealityStsRestClientConfiguration +from .operations import MixedRealityStsRestClientOperationsMixin +from . import models + + +class MixedRealityStsRestClient(MixedRealityStsRestClientOperationsMixin): + """Definition for the Mixed Reality Cloud STS service APIs. + + :param str base_url: Service URL + """ + + def __init__( + self, + base_url=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> None + if not base_url: + base_url = 'https://sts.mixedreality.azure.com' + self._config = MixedRealityStsRestClientConfiguration(**kwargs) + self._client = PipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + + def close(self): + # type: () -> None + self._client.close() + + def __enter__(self): + # type: () -> MixedRealityStsRestClient + self._client.__enter__() + return self + + def __exit__(self, *exc_details): + # type: (Any) -> None + self._client.__exit__(*exc_details) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/__init__.py new file mode 100644 index 000000000000..17251fcb2dbf --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._mixed_reality_sts_rest_client import MixedRealityStsRestClient +__all__ = ['MixedRealityStsRestClient'] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_configuration.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_configuration.py new file mode 100644 index 000000000000..6045303ca6c1 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_configuration.py @@ -0,0 +1,45 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional + +from azure.core.configuration import Configuration +from azure.core.pipeline import policies + +VERSION = "unknown" + +class MixedRealityStsRestClientConfiguration(Configuration): + """Configuration for MixedRealityStsRestClient. + + Note that all parameters used to create this instance are saved as instance + attributes. + + """ + + def __init__( + self, + **kwargs: Any + ) -> None: + super(MixedRealityStsRestClientConfiguration, self).__init__(**kwargs) + + kwargs.setdefault('sdk_moniker', 'mixedrealitystsrestclient/{}'.format(VERSION)) + self._configure(**kwargs) + + def _configure( + self, + **kwargs: Any + ) -> None: + self.user_agent_policy = kwargs.get('user_agent_policy') or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get('headers_policy') or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get('proxy_policy') or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get('logging_policy') or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get('http_logging_policy') or policies.HttpLoggingPolicy(**kwargs) + self.retry_policy = kwargs.get('retry_policy') or policies.AsyncRetryPolicy(**kwargs) + self.custom_hook_policy = kwargs.get('custom_hook_policy') or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get('redirect_policy') or policies.AsyncRedirectPolicy(**kwargs) + self.authentication_policy = kwargs.get('authentication_policy') diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_mixed_reality_sts_rest_client.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_mixed_reality_sts_rest_client.py new file mode 100644 index 000000000000..593e47542967 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/_mixed_reality_sts_rest_client.py @@ -0,0 +1,49 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Optional + +from azure.core import AsyncPipelineClient +from msrest import Deserializer, Serializer + +from ._configuration import MixedRealityStsRestClientConfiguration +from .operations import MixedRealityStsRestClientOperationsMixin +from .. import models + + +class MixedRealityStsRestClient(MixedRealityStsRestClientOperationsMixin): + """Definition for the Mixed Reality Cloud STS service APIs. + + :param str base_url: Service URL + """ + + def __init__( + self, + base_url: Optional[str] = None, + **kwargs: Any + ) -> None: + if not base_url: + base_url = 'https://sts.mixedreality.azure.com' + self._config = MixedRealityStsRestClientConfiguration(**kwargs) + self._client = AsyncPipelineClient(base_url=base_url, config=self._config, **kwargs) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False + self._deserialize = Deserializer(client_models) + + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "MixedRealityStsRestClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details) -> None: + await self._client.__aexit__(*exc_details) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/__init__.py new file mode 100644 index 000000000000..56b55f918c06 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/__init__.py @@ -0,0 +1,13 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._mixed_reality_sts_rest_client_operations import MixedRealityStsRestClientOperationsMixin + +__all__ = [ + 'MixedRealityStsRestClientOperationsMixin', +] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/_mixed_reality_sts_rest_client_operations.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/_mixed_reality_sts_rest_client_operations.py new file mode 100644 index 000000000000..90031d443396 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/aio/operations/_mixed_reality_sts_rest_client_operations.py @@ -0,0 +1,89 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import Any, Callable, Dict, Generic, Optional, TypeVar +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest + +from ... import models as _models + +T = TypeVar('T') +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + +class MixedRealityStsRestClientOperationsMixin: + + async def get_token( + self, + account_id: str, + api_version: Optional[str] = "2019-02-28-preview", + token_request_options: Optional["_models.TokenRequestOptions"] = None, + **kwargs + ) -> "_models.StsTokenResponseMessage": + """Gets an access token to be used with Mixed Reality services. + + Gets an access token to be used with Mixed Reality services. + + :param account_id: The Mixed Reality account identifier. + :type account_id: str + :param api_version: Api Version. + :type api_version: str + :param token_request_options: Parameter group. + :type token_request_options: ~azure.mixedreality.authentication._generated.models.TokenRequestOptions + :keyword callable cls: A custom type or function that will be passed the direct response + :return: StsTokenResponseMessage, or the result of cls(response) + :rtype: ~azure.mixedreality.authentication._generated.models.StsTokenResponseMessage + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.StsTokenResponseMessage"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + + _client_request_id = None + if token_request_options is not None: + _client_request_id = token_request_options.client_request_id + accept = "application/json" + + # Construct URL + url = self.get_token.metadata['url'] # type: ignore + path_format_arguments = { + 'accountId': self._serialize.url("account_id", account_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + if api_version is not None: + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + if _client_request_id is not None: + header_parameters['X-MRC-CV'] = self._serialize.header("client_request_id", _client_request_id, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + response_headers = {} + response_headers['MS-CV']=self._deserialize('str', response.headers.get('MS-CV')) + deserialized = self._deserialize('StsTokenResponseMessage', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) + + return deserialized + get_token.metadata = {'url': '/Accounts/{accountId}/token'} # type: ignore diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/__init__.py new file mode 100644 index 000000000000..6e706bc24cdc --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import StsTokenResponseMessage + from ._models_py3 import TokenRequestOptions +except (SyntaxError, ImportError): + from ._models import StsTokenResponseMessage # type: ignore + from ._models import TokenRequestOptions # type: ignore + +__all__ = [ + 'StsTokenResponseMessage', + 'TokenRequestOptions', +] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models.py new file mode 100644 index 000000000000..2b8d812be323 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models.py @@ -0,0 +1,54 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import msrest.serialization + + +class StsTokenResponseMessage(msrest.serialization.Model): + """Represents a token response message from the STS service. + + All required parameters must be populated in order to send to Azure. + + :param access_token: Required. An access token for the account. + :type access_token: str + """ + + _validation = { + 'access_token': {'required': True}, + } + + _attribute_map = { + 'access_token': {'key': 'AccessToken', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(StsTokenResponseMessage, self).__init__(**kwargs) + self.access_token = kwargs['access_token'] + + +class TokenRequestOptions(msrest.serialization.Model): + """Parameter group. + + :param client_request_id: The client request correlation vector, which should be set to a new + value for each request. Useful when debugging with Microsoft. + :type client_request_id: str + """ + + _attribute_map = { + 'client_request_id': {'key': 'clientRequestId', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(TokenRequestOptions, self).__init__(**kwargs) + self.client_request_id = kwargs.get('client_request_id', None) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models_py3.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models_py3.py new file mode 100644 index 000000000000..5ecff28c8992 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/models/_models_py3.py @@ -0,0 +1,60 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Optional + +import msrest.serialization + + +class StsTokenResponseMessage(msrest.serialization.Model): + """Represents a token response message from the STS service. + + All required parameters must be populated in order to send to Azure. + + :param access_token: Required. An access token for the account. + :type access_token: str + """ + + _validation = { + 'access_token': {'required': True}, + } + + _attribute_map = { + 'access_token': {'key': 'AccessToken', 'type': 'str'}, + } + + def __init__( + self, + *, + access_token: str, + **kwargs + ): + super(StsTokenResponseMessage, self).__init__(**kwargs) + self.access_token = access_token + + +class TokenRequestOptions(msrest.serialization.Model): + """Parameter group. + + :param client_request_id: The client request correlation vector, which should be set to a new + value for each request. Useful when debugging with Microsoft. + :type client_request_id: str + """ + + _attribute_map = { + 'client_request_id': {'key': 'clientRequestId', 'type': 'str'}, + } + + def __init__( + self, + *, + client_request_id: Optional[str] = None, + **kwargs + ): + super(TokenRequestOptions, self).__init__(**kwargs) + self.client_request_id = client_request_id diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/__init__.py new file mode 100644 index 000000000000..56b55f918c06 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/__init__.py @@ -0,0 +1,13 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from ._mixed_reality_sts_rest_client_operations import MixedRealityStsRestClientOperationsMixin + +__all__ = [ + 'MixedRealityStsRestClientOperationsMixin', +] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/_mixed_reality_sts_rest_client_operations.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/_mixed_reality_sts_rest_client_operations.py new file mode 100644 index 000000000000..8b8628e0c285 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/operations/_mixed_reality_sts_rest_client_operations.py @@ -0,0 +1,94 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +import warnings + +from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error +from azure.core.pipeline import PipelineResponse +from azure.core.pipeline.transport import HttpRequest, HttpResponse + +from .. import models as _models + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Callable, Dict, Generic, Optional, TypeVar + + T = TypeVar('T') + ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +class MixedRealityStsRestClientOperationsMixin(object): + + def get_token( + self, + account_id, # type: str + api_version="2019-02-28-preview", # type: Optional[str] + token_request_options=None, # type: Optional["_models.TokenRequestOptions"] + **kwargs # type: Any + ): + # type: (...) -> "_models.StsTokenResponseMessage" + """Gets an access token to be used with Mixed Reality services. + + Gets an access token to be used with Mixed Reality services. + + :param account_id: The Mixed Reality account identifier. + :type account_id: str + :param api_version: Api Version. + :type api_version: str + :param token_request_options: Parameter group. + :type token_request_options: ~azure.mixedreality.authentication._generated.models.TokenRequestOptions + :keyword callable cls: A custom type or function that will be passed the direct response + :return: StsTokenResponseMessage, or the result of cls(response) + :rtype: ~azure.mixedreality.authentication._generated.models.StsTokenResponseMessage + :raises: ~azure.core.exceptions.HttpResponseError + """ + cls = kwargs.pop('cls', None) # type: ClsType["_models.StsTokenResponseMessage"] + error_map = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError + } + error_map.update(kwargs.pop('error_map', {})) + + _client_request_id = None + if token_request_options is not None: + _client_request_id = token_request_options.client_request_id + accept = "application/json" + + # Construct URL + url = self.get_token.metadata['url'] # type: ignore + path_format_arguments = { + 'accountId': self._serialize.url("account_id", account_id, 'str'), + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} # type: Dict[str, Any] + if api_version is not None: + query_parameters['api-version'] = self._serialize.query("api_version", api_version, 'str') + + # Construct headers + header_parameters = {} # type: Dict[str, Any] + if _client_request_id is not None: + header_parameters['X-MRC-CV'] = self._serialize.header("client_request_id", _client_request_id, 'str') + header_parameters['Accept'] = self._serialize.header("accept", accept, 'str') + + request = self._client.get(url, query_parameters, header_parameters) + pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + response_headers = {} + response_headers['MS-CV']=self._deserialize('str', response.headers.get('MS-CV')) + deserialized = self._deserialize('StsTokenResponseMessage', pipeline_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) + + return deserialized + get_token.metadata = {'url': '/Accounts/{accountId}/token'} # type: ignore diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/py.typed b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/py.typed new file mode 100644 index 000000000000..e5aff4f83af8 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_generated/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/__init__.py new file mode 100644 index 000000000000..5b396cd202e8 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/__init__.py @@ -0,0 +1,5 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/__init__.py new file mode 100644 index 000000000000..5b396cd202e8 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/__init__.py @@ -0,0 +1,5 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixed_reality_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixed_reality_token_credential.py new file mode 100644 index 000000000000..7cc4e98d8bc6 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixed_reality_token_credential.py @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +from azure.mixedreality.authentication.aio import MixedRealityStsClient +from .static_access_token_credential import StaticAccessTokenCredential + +if TYPE_CHECKING: + from typing import Any + from azure.core.credentials import AccessToken + from azure.core.credentials_async import AsyncTokenCredential + +def get_mixedreality_credential( + account_id: str, + account_domain: str, + endpoint_url: str, + credential: "AsyncTokenCredential", + **kwargs): + if isinstance(credential, StaticAccessTokenCredential): + return credential + + return MixedRealityTokenCredential( + account_id=account_id, + account_domain=account_domain, + endpoint_url=endpoint_url, + credential=credential, + **kwargs) + + +class MixedRealityTokenCredential(object): + """ Represents a token credential that can be used to access a Mixed Reality service. + This implements the TokenCredential protocol. + + :param str account_id: The Mixed Reality service account identifier. + :param str endpoint_url: The Mixed Reality STS service endpoint. + :param TokenCredential credential: The credential used to access the Mixed Reality service. + """ + + def __init__( + self, + account_id: str, + account_domain: str, + endpoint_url: str, + credential: "AsyncTokenCredential", + **kwargs): + self.stsClient = MixedRealityStsClient( + account_id=account_id, + account_domain=account_domain, + endpoint_url=endpoint_url, + credential=credential, + **kwargs) + + async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": #pylint: disable=unused-argument + return await self.stsClient.get_token(**kwargs) + + async def close(self) -> None: + self.stsClient.close() + + async def __aenter__(self): + await self.stsClient.__aenter__() + return self + + async def __aexit__(self, exc_type, exc_value, traceback) -> None: + await self.stsClient.__aexit__() diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixedreality_account_key_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixedreality_account_key_credential.py new file mode 100644 index 000000000000..2f9efb559a53 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/mixedreality_account_key_credential.py @@ -0,0 +1,54 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +from datetime import date, datetime + +from azure.core.credentials import AccessToken + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + from azure.core.credentials import AzureKeyCredential + +ACCOUNT_KEY_VALID_YEARS = 10 + +class MixedRealityAccountKeyCredential(object): + """ Represents an object used for Mixed Reality account key authentication. + + :param str account_id: The Mixed Reality service account identifier. + :param AzureKeyCredential account_key: The Mixed Reality service account primary or secondary key credential. + """ + + def __init__(self, account_id, account_key): + # type: (str, AzureKeyCredential) -> None + self.account_id = account_id + self.account_key = account_key + + async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": #pylint: disable=unused-argument + token = self.account_id + ":" + self.account_key.key + + # No way to know when an account key might expire, so we'll set the + # access token wrapping it to expire 10 years in the future. + expiration_date = _add_years(datetime.now(), ACCOUNT_KEY_VALID_YEARS) + expiration_timestamp = int(expiration_date.timestamp()) + + return AccessToken(token, expiration_timestamp) + + async def close(self) -> None: + pass + + async def __aenter__(self): + pass + + async def __aexit__(self, exc_type, exc_value, traceback) -> None: + pass + +def _add_years(date_to_update, years): + try: + return date_to_update.replace(year=date_to_update.year + years) + except ValueError: + return date_to_update + (date(date_to_update.year + years, 1, 1) - date(date_to_update.year, 1, 1)) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/static_access_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/static_access_token_credential.py new file mode 100644 index 000000000000..fccbd6f1a2b0 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/aio/static_access_token_credential.py @@ -0,0 +1,38 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + from azure.core.credentials_async import AsyncTokenCredential + from azure.core.credentials import AccessToken + +class StaticAccessTokenCredential(object): + """ Represents a static access token credential. + This implements the AsyncTokenCredential protocol. + + :param AccessToken access_token: An access token. + """ + + def __init__(self, access_token: "AccessToken"): + self._access_token = access_token + + async def get_token( + self, + #pylint: disable=unused-argument + *scopes: str, + **kwargs: "Any") -> "AccessToken": + return self._access_token + + async def close(self) -> None: + pass + + async def __aenter__(self): + pass + + async def __aexit__(self, exc_type, exc_value, traceback) -> None: + pass diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/authentication_endpoint.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/authentication_endpoint.py new file mode 100644 index 000000000000..72bdcc70fd96 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/authentication_endpoint.py @@ -0,0 +1,9 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +def construct_endpoint_url(account_domain): + # type: (str) -> str + return 'https://sts.' + account_domain diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixed_reality_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixed_reality_token_credential.py new file mode 100644 index 000000000000..e0bb1dda3627 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixed_reality_token_credential.py @@ -0,0 +1,50 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +from azure.mixedreality.authentication import MixedRealityStsClient +from .static_access_token_credential import StaticAccessTokenCredential + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any, Union + from azure.core.credentials import AccessToken, TokenCredential + + +def get_mixedreality_credential(account_id, account_domain, endpoint_url, credential, **kwargs): + # type: (str, str, str, TokenCredential, Any) -> TokenCredential + if isinstance(credential, StaticAccessTokenCredential): + return credential + + return MixedRealityTokenCredential( + account_id=account_id, + account_domain=account_domain, + endpoint_url=endpoint_url, + credential=credential, + **kwargs) + + +class MixedRealityTokenCredential(object): + """ Represents a token credential that can be used to access a Mixed Reality service. + This implements the TokenCredential protocol. + + :param str account_id: The Mixed Reality service account identifier. + :param str endpoint_url: The Mixed Reality STS service endpoint. + :param TokenCredential credential: The credential used to access the Mixed Reality service. + """ + + def __init__(self, account_id, account_domain, endpoint_url, credential, **kwargs): + # type: (str, str, str, TokenCredential, Any) -> None + self.stsClient = MixedRealityStsClient( + account_id=account_id, + account_domain=account_domain, + endpoint_url=endpoint_url, + credential=credential, + **kwargs) + + def get_token(self, *scopes, **kwargs): #pylint: disable=unused-argument + # type: (*str, **Any) -> AccessToken + return self.stsClient.get_token(**kwargs) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixedreality_account_key_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixedreality_account_key_credential.py new file mode 100644 index 000000000000..a7ec1ca5db63 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/mixedreality_account_key_credential.py @@ -0,0 +1,46 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING +from datetime import date, datetime +import time + +from azure.core.credentials import AzureKeyCredential, AccessToken + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + +ACCOUNT_KEY_VALID_YEARS = 10 + +class MixedRealityAccountKeyCredential(object): + """ Represents an object used for Mixed Reality account key authentication. + + :param str account_id: The Mixed Reality service account identifier. + :param AzureKeyCredential account_key: The Mixed Reality service account primary or secondary key credential. + """ + + def __init__(self, account_id, account_key): + # type: (str, AzureKeyCredential) -> None + self.account_id = account_id + self.account_key = account_key + + def get_token(self, *scopes, **kwargs): #pylint: disable=unused-argument + # type: (*str, **Any) -> AccessToken + + token = self.account_id + ":" + self.account_key.key + + # No way to know when an account key might expire, so we'll set the + # access token wrapping it to expire 10 years in the future. + expiration_date = _add_years(datetime.now(), ACCOUNT_KEY_VALID_YEARS) + expiration_timestamp = int(time.mktime(expiration_date.timetuple())) + + return AccessToken(token, expiration_timestamp) + +def _add_years(date_to_update, years): + try: + return date_to_update.replace(year=date_to_update.year + years) + except ValueError: + return date_to_update + (date(date_to_update.year + years, 1, 1) - date(date_to_update.year, 1, 1)) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/static_access_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/static_access_token_credential.py new file mode 100644 index 000000000000..712f4e20738f --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_shared/static_access_token_credential.py @@ -0,0 +1,27 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from typing import Any + from azure.core.credentials import TokenCredential + from azure.core.credentials import AccessToken + +class StaticAccessTokenCredential(object): + """ Represents a static access token credential. + This implements the TokenCredential protocol. + + :param AccessToken access_token: An access token. + """ + + def __init__(self, access_token): + # type: (AccessToken) -> None + self._access_token = access_token + + def get_token(self, *scopes, **kwargs): #pylint: disable=unused-argument + # type: (*str, **Any) -> AccessToken + return self._access_token diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_utils.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_utils.py new file mode 100644 index 000000000000..9a016a0692a7 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_utils.py @@ -0,0 +1,73 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import base64 +import json +import random + +from azure.core.credentials import AccessToken + +from ._generated.models import StsTokenResponseMessage + + +def convert_to_access_token(token_response_message): + # type: (StsTokenResponseMessage) -> AccessToken + """ + Converts the specified token response message to an AccessToken. + """ + if not token_response_message: + raise ValueError("token_response_message must be a non-empty string.") + + expiration_timestamp = retrieve_jwt_expiration_timestamp(token_response_message.access_token) + + return AccessToken(token_response_message.access_token, expiration_timestamp) + +def retrieve_jwt_expiration_timestamp(jwt_value): + # type: (str) -> int + """ + Retrieves the expiration value from the JWT. + + :param str jwt_value: The JWT value. + :returns: int + """ + if not jwt_value: + raise ValueError("jwt_value must be a non-empty string.") + + parts = jwt_value.split(".") + + if len(parts) < 3: + raise ValueError("Invalid JWT structure. Expected a JWS Compact Serialization formatted value.") + + try: + padded_base64_payload = base64.b64decode(parts[1]).decode('utf-8') + payload = json.loads(padded_base64_payload) + except ValueError: + raise ValueError("Unable to decode the JWT.") + + try: + exp = payload['exp'] + except KeyError: + raise ValueError("Invalid JWT payload structure. No expiration.") + + return int(exp) + +BASE_64_CHAR_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +CV_BASE_LENGTH = 22 + +def generate_cv_base(): + # type: () -> str + """ + Seed function to randomly generate a 16 character base64 encoded string for + the Correlation Vector's base value. + """ + result = '' + + #pylint: disable=unused-variable + for i in range(CV_BASE_LENGTH): + random_index = random.randint(0, len(BASE_64_CHAR_SET) - 1) + result += BASE_64_CHAR_SET[random_index] + + return result diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_version.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_version.py new file mode 100644 index 000000000000..14cf0981d001 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/_version.py @@ -0,0 +1,10 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +# matches SEMVER +VERSION = "1.0.0b1" + +SDK_MONIKER = "mixedreality-authentication/{}".format(VERSION) # type: str diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/__init__.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/__init__.py new file mode 100644 index 000000000000..736dc1c08fe4 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/__init__.py @@ -0,0 +1,11 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from ._client_async import MixedRealityStsClient + +__all__ = [ + 'MixedRealityStsClient' +] diff --git a/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/_client_async.py b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/_client_async.py new file mode 100644 index 000000000000..fedbacccf397 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/azure/mixedreality/authentication/aio/_client_async.py @@ -0,0 +1,112 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +# pylint: disable=unused-import,ungrouped-imports +from typing import Any, TYPE_CHECKING, Union + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse # type: ignore + +from azure.core.credentials import AzureKeyCredential +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.pipeline.policies import AsyncBearerTokenCredentialPolicy + +from .._generated.aio import MixedRealityStsRestClient +from .._generated.models import TokenRequestOptions +from .._version import SDK_MONIKER +from .._shared.authentication_endpoint import construct_endpoint_url +from .._shared.aio.mixedreality_account_key_credential import MixedRealityAccountKeyCredential +from .._utils import convert_to_access_token, generate_cv_base + +if TYPE_CHECKING: + from azure.core.credentials import AccessToken + from azure.core.credentials_async import AsyncTokenCredential + + +class MixedRealityStsClient(object): + """ A client to interact with the Mixed Reality STS service. + + :param str account_id: + The Mixed Reality service account identifier. + :param str account_domain: + The Mixed Reality service account domain. + :param Union[TokenCredential, AzureKeyCredential] credential: + The credential used to access the Mixed Reality service. + :keyword str custom_endpoint_url: + Override the Mixed Reality STS service endpoint. + """ + + def __init__(self, + account_id: str, + account_domain: str, + credential: Union[AzureKeyCredential, "AsyncTokenCredential"], #pylint: disable=unsubscriptable-object + **kwargs) -> None: + if not account_id: + raise ValueError("account_id must be a non-empty string.") + + if not account_domain: + raise ValueError("account_domain must be a non-empty string.") + + if not credential: + raise ValueError("credential can not be None.") + + self._account_id = account_id + self._account_domain = account_domain + + if isinstance(credential, AzureKeyCredential): + credential = MixedRealityAccountKeyCredential(account_id, credential) + + self._credential = credential + + endpoint_url = kwargs.pop('custom_endpoint_url', construct_endpoint_url(account_domain)) + + try: + if not endpoint_url.lower().startswith('http'): + endpoint_url = "https://" + endpoint_url + except AttributeError as ex: + raise ValueError("Host URL must be a string.") from ex + + parsed_url = urlparse(endpoint_url.rstrip('/')) + if not parsed_url.netloc: + raise ValueError("Invalid URL: {}".format(endpoint_url)) + + self._endpoint_url = endpoint_url + + authentication_policy = AsyncBearerTokenCredentialPolicy(credential, [endpoint_url + '/.default']) + + self._client = MixedRealityStsRestClient( + base_url=endpoint_url, + authentication_policy=authentication_policy, + sdk_moniker=SDK_MONIKER, + **kwargs) + + @distributed_trace_async + async def get_token(self, **kwargs) -> "AccessToken": + """ + Retrieve a token from the STS service for the specified account identifier asynchronously. + :return: Instance of azure.core.credentials.AccessToken - token and expiry date of it + :rtype: :class:`azure.core.credentials.AccessToken` + """ + token_request_options = TokenRequestOptions() + token_request_options.client_request_id = generate_cv_base() + + response = await self._client.get_token( + self._account_id, + token_request_options=token_request_options, + **kwargs) + return convert_to_access_token(response) + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> "MixedRealityStsClient": + await self._client.__aenter__() + return self + + async def __aexit__(self, *args) -> None: + await self._client.__aexit__(*args) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/dev_requirements.txt b/sdk/mixedreality/azure-mixedreality-authentication/dev_requirements.txt new file mode 100644 index 000000000000..d9b5454b3434 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/dev_requirements.txt @@ -0,0 +1,4 @@ +-e ../../../tools/azure-sdk-tools +../azure-mixedreality-nspkg +../../core/azure-core +aiohttp>=3.0; python_version >= '3.5' diff --git a/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample async.py b/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample async.py new file mode 100644 index 000000000000..5dc595bc2f3e --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample async.py @@ -0,0 +1,70 @@ + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: client_sample_async.py +DESCRIPTION: + These samples demonstrate creating a client and requesting a token. + +USAGE: + python client_sample_async.py + Set the environment variables with your own values before running the sample: + 1) MIXEDREALITY_ACCOUNT_DOMAIN - the Mixed Reality account domain. + 2) MIXEDREALITY_ACCOUNT_ID - the Mixed Reality account identifier. + 3) MIXEDREALITY_ACCOUNT_KEY - the Mixed Reality account primary or secondary key. +""" + + +import os +import asyncio + + +class ClientSamplesAsync(object): + from azure.core.credentials import AzureKeyCredential + + account_domain = os.environ.get("MIXEDREALITY_ACCOUNT_DOMAIN", None) + if not account_domain: + raise ValueError("Set MIXEDREALITY_ACCOUNT_DOMAIN env before run this sample.") + + account_id = os.environ.get("MIXEDREALITY_ACCOUNT_ID", None) + if not account_id: + raise ValueError("Set MIXEDREALITY_ACCOUNT_ID env before run this sample.") + + account_key = os.environ.get("MIXEDREALITY_ACCOUNT_KEY", None) + if not account_key: + raise ValueError("Set MIXEDREALITY_ACCOUNT_KEY env before run this sample.") + + key_credential = AzureKeyCredential(account_key) + + def create_client(self): + # [START create_client] + from azure.mixedreality.authentication.aio import MixedRealityStsClient + client = MixedRealityStsClient(self.account_id, self.account_domain, self.key_credential) + # [END create_client] + + print("client created") + + async def get_token(self): + from azure.mixedreality.authentication.aio import MixedRealityStsClient + client = MixedRealityStsClient(self.account_id, self.account_domain, self.key_credential) + + async with client: + # [START get_token] + access_token = await client.get_token() + # [END get_token] + + print("token retrieved: " + access_token.token) + + +async def main(): + sample = ClientSamplesAsync() + sample.create_client() + await sample.get_token() + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample.py b/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample.py new file mode 100644 index 000000000000..0de0e21a39de --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/samples/client_sample.py @@ -0,0 +1,63 @@ + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +""" +FILE: client_sample.py +DESCRIPTION: + These samples demonstrate creating a client and requesting a token. + +USAGE: + python client_sample.py + Set the environment variables with your own values before running the sample: + 1) MIXEDREALITY_ACCOUNT_DOMAIN - the Mixed Reality account domain. + 2) MIXEDREALITY_ACCOUNT_ID - the Mixed Reality account identifier. + 3) MIXEDREALITY_ACCOUNT_KEY - the Mixed Reality account primary or secondary key. +""" + + +import os + + +class ClientSamples(object): + from azure.core.credentials import AzureKeyCredential + + account_domain = os.environ.get("MIXEDREALITY_ACCOUNT_DOMAIN", None) + if not account_domain: + raise ValueError("Set MIXEDREALITY_ACCOUNT_DOMAIN env before run this sample.") + + account_id = os.environ.get("MIXEDREALITY_ACCOUNT_ID", None) + if not account_id: + raise ValueError("Set MIXEDREALITY_ACCOUNT_ID env before run this sample.") + + account_key = os.environ.get("MIXEDREALITY_ACCOUNT_KEY", None) + if not account_key: + raise ValueError("Set MIXEDREALITY_ACCOUNT_KEY env before run this sample.") + + key_credential = AzureKeyCredential(account_key) + + def create_client(self): + # [START create_client] + from azure.mixedreality.authentication import MixedRealityStsClient + client = MixedRealityStsClient(self.account_id, self.account_domain, self.key_credential) + # [END create_client] + + print("client created") + + def get_token(self): + # [START get_token] + from azure.mixedreality.authentication import MixedRealityStsClient + client = MixedRealityStsClient(self.account_id, self.account_domain, self.key_credential) + access_token = client.get_token() + # [END get_token] + + print("token retrieved: " + access_token.token) + + +if __name__ == '__main__': + sample = ClientSamples() + sample.create_client() + sample.get_token() diff --git a/sdk/mixedreality/azure-mixedreality-authentication/sdk_packaging.toml b/sdk/mixedreality/azure-mixedreality-authentication/sdk_packaging.toml new file mode 100644 index 000000000000..2684d587e162 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/sdk_packaging.toml @@ -0,0 +1,7 @@ +[packaging] +auto_update = false +package_name = "azure-mixedreality-authentication" +package_pprint_name = "Mixed Reality Authentication" +package_doc_id = "" +is_stable = false +is_arm = false diff --git a/sdk/mixedreality/azure-mixedreality-authentication/setup.cfg b/sdk/mixedreality/azure-mixedreality-authentication/setup.cfg new file mode 100644 index 000000000000..3c6e79cf31da --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/sdk/mixedreality/azure-mixedreality-authentication/setup.py b/sdk/mixedreality/azure-mixedreality-authentication/setup.py new file mode 100644 index 000000000000..0384e23bf7c8 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/setup.py @@ -0,0 +1,80 @@ +from setuptools import setup, find_packages +import os +from io import open +import re + +# example setup.py Feel free to copy the entire "azure-template" folder into a package folder named +# with "azure-". Ensure that the below arguments to setup() are updated to reflect +# your package. + +# this setup.py is set up in a specific way to keep the azure* and azure-mgmt-* namespaces WORKING all the way +# up from python 2.7. Reference here: https://github.com/Azure/azure-sdk-for-python/wiki/Azure-packaging + +PACKAGE_NAME = "azure-mixedreality-authentication" +PACKAGE_PPRINT_NAME = "Mixed Reality Authentication" + +# a-b-c => a/b/c +package_folder_path = PACKAGE_NAME.replace('-', '/') +# a-b-c => a.b.c +namespace_name = PACKAGE_NAME.replace('-', '.') + +# Version extraction inspired from 'requests' +with open(os.path.join(package_folder_path, '_version.py'), 'r') as fd: + version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', + fd.read(), re.MULTILINE).group(1) +if not version: + raise RuntimeError('Cannot find version information') + +with open('README.md', encoding='utf-8') as f: + readme = f.read() + +with open('CHANGELOG.md', encoding='utf-8') as f: + changelog = f.read() + +setup( + name=PACKAGE_NAME, + version=version, + description='Microsoft Azure {} Client Library for Python'.format(PACKAGE_PPRINT_NAME), + + # ensure that these are updated to reflect the package owners' information + long_description=readme + "\n\n" + changelog, + long_description_content_type='text/markdown', + url='https://github.com/Azure/azure-sdk-for-python', + author='Microsoft Corporation', + author_email='azuresdkengsysadmins@microsoft.com', + + license='MIT License', + # ensure that the development status reflects the status of your package + classifiers=[ + "Development Status :: 4 - Beta", + + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'License :: OSI Approved :: MIT License', + ], + packages=find_packages(exclude=[ + 'tests', + # Exclude packages that will be covered by PEP420 or nspkg + 'azure', + 'azure.mixedreality' + ]), + install_requires=[ + 'azure-core<2.0.0,>=1.2.2', + 'msrest>=0.5.0' + ], + extras_require={ + ":python_version<'3.0'": ['azure-mixedreality-nspkg'], + ":python_version<'3.5'": ["typing"] + }, + project_urls={ + 'Bug Reports': 'https://github.com/Azure/azure-sdk-for-python/issues', + 'Source': 'https://github.com/Azure/azure-sdk-python', + } +) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/swagger/SWAGGER.md b/sdk/mixedreality/azure-mixedreality-authentication/swagger/SWAGGER.md new file mode 100644 index 000000000000..40af809e4840 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/swagger/SWAGGER.md @@ -0,0 +1,30 @@ +# Azure Mixed Reality Authentication Service client library for Python + +## Setup + +```ps +npm install -g autorest +``` + +## Generation + +```ps +cd +autorest SWAGGER.md +``` + +### Code generation settings + +```yaml +title: MixedRealityStsRestClient +input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/aa19725fe79aea2a9dc580f3c66f77f89cc34563/specification/mixedreality/data-plane/Microsoft.MixedReality/preview/2019-02-28-preview/mr-sts.json +output-folder: ../azure/mixedreality/authentication/_generated +namespace: azure.mixedreality.authentication._generated +no-namespace-folders: true +license-header: MICROSOFT_MIT_NO_VERSION +enable-xml: false +clear-output-folder: true +python: true +v3: true +add-credentials: false +``` diff --git a/sdk/mixedreality/azure-mixedreality-authentication/swagger/update.ps1 b/sdk/mixedreality/azure-mixedreality-authentication/swagger/update.ps1 new file mode 100644 index 000000000000..a7490a9848d1 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/swagger/update.ps1 @@ -0,0 +1,6 @@ +Push-Location $PSScriptRoot +try { + & autorest SWAGGER.md +} finally { + Pop-Location +} diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/_constants.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/_constants.py new file mode 100644 index 000000000000..9de02c451788 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/_constants.py @@ -0,0 +1,10 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +# Fake account details matching recordings. +MIXEDREALITY_ACCOUNT_DOMAIN="mixedreality.azure.com" +MIXEDREALITY_ACCOUNT_ID="68321d5a-7978-4ceb-b880-0f49751daae9" +MIXEDREALITY_ACCOUNT_KEY="NjgzMjFkNWEtNzk3OC00Y2ViLWI4ODAtMGY0OTc1MWRhYWU5" \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/conftest.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/conftest.py new file mode 100644 index 000000000000..9f69fcac8bdc --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/conftest.py @@ -0,0 +1,11 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import sys + +# Ignore collection of async tests for Python 2 +collect_ignore_glob = [] +if sys.version_info < (3, 5): + collect_ignore_glob.append("*_async.py") diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client.test_get_token.yaml b/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client.test_get_token.yaml new file mode 100644 index 000000000000..6be3baa36955 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client.test_get_token.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-mixedreality-authentication/1.0.0b1 Python/3.9.1 (Windows-10-10.0.19041-SP0) + X-MRC-CV: + - z2TH5gImRhQCZc4ubhqtRV + method: GET + uri: https://sts.mixedreality.azure.com/Accounts/68321d5a-7978-4ceb-b880-0f49751daae9/token?api-version=2019-02-28-preview + response: + body: + string: '{"AccessToken":"eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZmF1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYwNzk3ODY4MyIsIm5iZiI6IjE2MDc5Nzg2ODMiLCJleHAiOiIxNjA3OTc4OTgzIn0=."}' + headers: + cache-control: + - no-store,no-cache + content-length: + - '1264' + content-type: + - application/json; charset=utf-8 + date: + - Thu, 28 Jan 2021 01:56:10 GMT + ms-cv: + - gKXl1CkeG0mRb6HEtMUmHQ.0 + pragma: + - no-cache + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client_async.test_get_token.yaml b/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client_async.test_get_token.yaml new file mode 100644 index 000000000000..32b3c3b0e66c --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/recordings/test_client_async.test_get_token.yaml @@ -0,0 +1,28 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + User-Agent: + - azsdk-python-mixedreality-authentication/1.0.0b1 Python/3.9.1 (Windows-10-10.0.19041-SP0) + X-MRC-CV: + - DOGUG9rex0lylvLZmhuJgR + method: GET + uri: https://sts.mixedreality.azure.com/Accounts/68321d5a-7978-4ceb-b880-0f49751daae9/token?api-version=2019-02-28-preview + response: + body: + string: '{"AccessToken":"eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZmF1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYwNzk3ODY4MyIsIm5iZiI6IjE2MDc5Nzg2ODMiLCJleHAiOiIxNjA3OTc4OTgzIn0=."}' + headers: + cache-control: no-store,no-cache + content-length: '1264' + content-type: application/json; charset=utf-8 + date: Thu, 28 Jan 2021 18:31:51 GMT + ms-cv: K89E7J8QQ0qfkjIiukWztw.0 + pragma: no-cache + x-content-type-options: nosniff + status: + code: 200 + message: OK + url: https://sts.mixedreality.azure.com/Accounts/68321d5a-7978-4ceb-b880-0f49751daae9/token?api-version=2019-02-28-preview +version: 1 diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client.py new file mode 100644 index 000000000000..33e4fee685df --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client.py @@ -0,0 +1,106 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import os +import pytest + +from devtools_testutils import AzureTestCase + +from azure.core.credentials import AzureKeyCredential +from azure.mixedreality.authentication import MixedRealityStsClient +from azure.mixedreality.authentication._shared.mixedreality_account_key_credential import MixedRealityAccountKeyCredential + +# Import fake account details matching recordings. +from _constants import ( + MIXEDREALITY_ACCOUNT_DOMAIN, + MIXEDREALITY_ACCOUNT_ID, + MIXEDREALITY_ACCOUNT_KEY +) + + +class ClientTests(AzureTestCase): + def __init__(self, *args, **kwargs): + super(ClientTests, self).__init__(*args, **kwargs) + self.account_domain = self.get_var('MIXEDREALITY_ACCOUNT_DOMAIN', MIXEDREALITY_ACCOUNT_DOMAIN) + self.account_id = self.get_var('MIXEDREALITY_ACCOUNT_ID', MIXEDREALITY_ACCOUNT_ID) + self.account_key = self.get_var('MIXEDREALITY_ACCOUNT_KEY', MIXEDREALITY_ACCOUNT_KEY) + self.key_credential = AzureKeyCredential(self.account_key) + + def setUp(self): + super(ClientTests, self).setUp() + + def tearDown(self): + super(ClientTests, self).tearDown() + + def get_var(self, variable_name, default_or_playback_value): + if self.is_live: + return os.environ.get(variable_name, default_or_playback_value) + + return default_or_playback_value + + def test_create_client(self): + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential) + + assert client is not None + + def test_create_client_custom_with_endpoint(self): + custom_endpoint_url = "https://my.custom.endpoint" + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential, + custom_endpoint_url=custom_endpoint_url) + + assert client._endpoint_url == custom_endpoint_url + + def test_create_client_with_credential(self): + token_credential = MixedRealityAccountKeyCredential(self.account_id, self.key_credential) + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=token_credential) + + assert client._credential == token_credential + + def test_create_client_with_invalid_arguments(self): + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=None, + account_domain=self.account_domain, + credential=self.key_credential) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=None, + credential=self.key_credential) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=None) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential, + custom_endpoint_url="#") + + def test_get_token(self): + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential) + + token = client.get_token() + + assert token is not None + assert token.token is not None + assert token.expires_on is not None diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client_async.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client_async.py new file mode 100644 index 000000000000..aeead54991fc --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_client_async.py @@ -0,0 +1,108 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import os +import pytest + +from devtools_testutils import AzureTestCase + +from azure.core.credentials import AzureKeyCredential +from azure.mixedreality.authentication.aio import MixedRealityStsClient +from azure.mixedreality.authentication._shared.aio.mixedreality_account_key_credential import MixedRealityAccountKeyCredential + +# Import fake account details matching recordings. +from _constants import ( + MIXEDREALITY_ACCOUNT_DOMAIN, + MIXEDREALITY_ACCOUNT_ID, + MIXEDREALITY_ACCOUNT_KEY +) + + +class ClientTests(AzureTestCase): + def __init__(self, *args, **kwargs): + super(ClientTests, self).__init__(*args, **kwargs) + self.account_domain = self.get_var('MIXEDREALITY_ACCOUNT_DOMAIN', MIXEDREALITY_ACCOUNT_DOMAIN) + self.account_id = self.get_var('MIXEDREALITY_ACCOUNT_ID', MIXEDREALITY_ACCOUNT_ID) + self.account_key = self.get_var('MIXEDREALITY_ACCOUNT_KEY', MIXEDREALITY_ACCOUNT_KEY) + self.key_credential = AzureKeyCredential(self.account_key) + + def setUp(self): + super(ClientTests, self).setUp() + + def tearDown(self): + super(ClientTests, self).tearDown() + + def get_var(self, variable_name, default_or_playback_value): + # type: (str, str) -> str + if self.is_live: + return os.environ.get(variable_name, default_or_playback_value) + + return default_or_playback_value + + def test_create_client(self): + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential) + + assert client is not None + + def test_create_client_custom_with_endpoint(self): + custom_endpoint_url = "https://my.custom.endpoint" + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential, + custom_endpoint_url=custom_endpoint_url) + + assert client._endpoint_url == custom_endpoint_url + + def test_create_client_with_credential(self): + token_credential = MixedRealityAccountKeyCredential(self.account_id, self.key_credential) + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=token_credential) + + assert client._credential == token_credential + + def test_create_client_with_invalid_arguments(self): + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=None, + account_domain=self.account_domain, + credential=self.key_credential) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=None, + credential=self.key_credential) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=None) + + with pytest.raises(ValueError): + MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential, + custom_endpoint_url="#") + + @AzureTestCase.await_prepared_test + async def test_get_token(self): + client = MixedRealityStsClient( + account_id=self.account_id, + account_domain=self.account_domain, + credential=self.key_credential) + + token = await client.get_token() + + assert token is not None + assert token.token is not None + assert token.expires_on is not None diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential.py new file mode 100644 index 000000000000..bb9b3b376c6a --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from azure.core.credentials import AccessToken, AzureKeyCredential + +from azure.mixedreality.authentication._shared.mixed_reality_token_credential import get_mixedreality_credential, MixedRealityTokenCredential +from azure.mixedreality.authentication._shared.static_access_token_credential import StaticAccessTokenCredential +from azure.mixedreality.authentication._shared.mixedreality_account_key_credential import MixedRealityAccountKeyCredential + +class TestMixedRealityTokenCredential: + def test_get_mixedreality_credential_static_credential(self): + access_token = AccessToken("My access token", 0) + credential = StaticAccessTokenCredential(access_token) + + actualCredential = get_mixedreality_credential( + account_id="account_id", + account_domain="account_domain", + endpoint_url="http://my.endpoint.url", + credential=credential) + + assert credential == actualCredential + + def test_get_mixedreality_credential_other_credential(self): + keyCredential = AzureKeyCredential("my_account_key") + credential = MixedRealityAccountKeyCredential("account_id", keyCredential) + + actualCredential = get_mixedreality_credential( + account_id="account_id", + account_domain="account_domain", + endpoint_url="http://my.endpoint.url", + credential=credential) + + assert credential != actualCredential + assert isinstance(actualCredential, MixedRealityTokenCredential) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential_async.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential_async.py new file mode 100644 index 000000000000..a7b2e02dc793 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_mixed_reality_token_credential_async.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from azure.core.credentials import AccessToken, AzureKeyCredential + +from azure.mixedreality.authentication._shared.aio.mixed_reality_token_credential import get_mixedreality_credential, MixedRealityTokenCredential +from azure.mixedreality.authentication._shared.aio.static_access_token_credential import StaticAccessTokenCredential +from azure.mixedreality.authentication._shared.aio.mixedreality_account_key_credential import MixedRealityAccountKeyCredential + +class TestMixedRealityTokenCredential: + def test_get_mixedreality_credential_static_credential(self): + access_token = AccessToken("My access token", 0) + credential = StaticAccessTokenCredential(access_token) + + actualCredential = get_mixedreality_credential( + account_id="account_id", + account_domain="account_domain", + endpoint_url="http://my.endpoint.url", + credential=credential) + + assert credential == actualCredential + + def test_get_mixedreality_credential_other_credential(self): + keyCredential = AzureKeyCredential("my_account_key") + credential = MixedRealityAccountKeyCredential("account_id", keyCredential) + + actualCredential = get_mixedreality_credential( + account_id="account_id", + account_domain="account_domain", + endpoint_url="http://my.endpoint.url", + credential=credential) + + assert credential != actualCredential + assert isinstance(actualCredential, MixedRealityTokenCredential) diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential.py new file mode 100644 index 000000000000..0511780951dd --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from azure.core.credentials import AccessToken + +from azure.mixedreality.authentication._shared.static_access_token_credential import StaticAccessTokenCredential + +class TestStaticAccessTokenCredential: + def test_get_token(self): + token = "My access token" + expiration = 0 + + access_token = AccessToken(token=token, expires_on=expiration) + staticAccessToken = StaticAccessTokenCredential(access_token) + + actual = staticAccessToken.get_token() + + assert access_token == actual diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential_async.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential_async.py new file mode 100644 index 000000000000..f9b7171460fd --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_static_access_token_credential_async.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from azure.core.credentials import AccessToken +from devtools_testutils import AzureTestCase + +from azure.mixedreality.authentication._shared.aio.static_access_token_credential import StaticAccessTokenCredential + +class TestAsyncStaticAccessTokenCredential: + @AzureTestCase.await_prepared_test + async def test_get_token(self): + token = "My access token" + expiration = 0 + + access_token = AccessToken(token=token, expires_on=expiration) + staticAccessToken = StaticAccessTokenCredential(access_token) + + actual = await staticAccessToken.get_token() + + assert access_token == actual diff --git a/sdk/mixedreality/azure-mixedreality-authentication/tests/test_utils.py b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_utils.py new file mode 100644 index 000000000000..17b31bcb87fa --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-authentication/tests/test_utils.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest + +from azure.mixedreality.authentication._utils import generate_cv_base, retrieve_jwt_expiration_timestamp + + +class TestUtils: + def test_generate_cv_base(self): + cv = generate_cv_base() + + assert cv is not None + assert len(cv) == 22 + + def test_generate_cv_base_are_random(self): + cv1 = generate_cv_base() + cv2 = generate_cv_base() + + assert cv1 is not None + assert cv2 is not None + assert cv1 != cv2 + + def test_retrieve_jwt_expiration_timestamp(self): + # Note: The trailing "." on the end indicates an empty signature indicating that this JWT is not signed. + jwt_value = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZmF1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYxMDgxMjI1MCIsIm5iZiI6IjE2MTA4MTI1NTAiLCJleHAiOiIxNjEwODk4NjUwIn0=." + expected_expiration_timestamp = 1610898650 # 1/17/2021 3:50:50 PM UTC + + actual = retrieve_jwt_expiration_timestamp(jwt_value) + + assert actual is not None + assert actual == expected_expiration_timestamp + + def test_retrieve_jwt_expiration_timestamp_invalid_parameter(self): + with pytest.raises(ValueError): + retrieve_jwt_expiration_timestamp(None) + + def test_retrieve_jwt_expiration_timestamp_invalid_structure(self): + # JWT value with missing signature section on the end. + jwt_value = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZmF1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYxMDgxMjI1MCIsIm5iZiI6IjE2MTA4MTI1NTAiLCJleHAiOiIxNjEwODk4NjUwIn0=" + + with pytest.raises(ValueError): + retrieve_jwt_expiration_timestamp(jwt_value) + + def test_retrieve_jwt_expiration_timestamp_invalid_payload(self): + # JWT value with missing payload. + jwt_value = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.." + + with pytest.raises(ValueError): + retrieve_jwt_expiration_timestamp(jwt_value) + + def test_retrieve_jwt_expiration_timestamp_invalid_exp(self): + # JWT value with missing expiration field. + jwt_value = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6IkJvYkBjb250b3NvLmNvbSIsImdpdmVuX25hbWUiOiJCb2IiLCJpc3MiOiJodHRwOi8vRGVmYXVsdC5Jc3N1ZXIuY29tIiwiYXVkIjoiaHR0cDovL0RlZmF1bHQuQXVkaWVuY2UuY29tIiwiaWF0IjoiMTYxMDgxMjI1MCIsIm5iZiI6IjE2MTA4MTI1NTAifQ==." + + with pytest.raises(ValueError): + retrieve_jwt_expiration_timestamp(jwt_value) diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/CHANGELOG.md b/sdk/mixedreality/azure-mixedreality-nspkg/CHANGELOG.md new file mode 100644 index 000000000000..627c355468b5 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History + +## 1.0.0 (Unreleased) + +- Initial release diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/MANIFEST.in b/sdk/mixedreality/azure-mixedreality-nspkg/MANIFEST.in new file mode 100644 index 000000000000..092b64f9159b --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/MANIFEST.in @@ -0,0 +1,3 @@ +include *.md +include azure/__init__.py +include azure/mixedreality/__init__.py \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/README.md b/sdk/mixedreality/azure-mixedreality-nspkg/README.md new file mode 100644 index 000000000000..995038c70840 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/README.md @@ -0,0 +1,11 @@ +# Microsoft Azure Mixed Reality SDK for Python + +This is the Microsoft Azure Mixed Reality namespace package. + +This package is not intended to be installed directly by the end user. + +It provides the necessary files for other packages to extend the +azure.mixedreality namespace. + +The complete list of available packages can be found at: +https://aka.ms/azsdk/python/all diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/azure/__init__.py b/sdk/mixedreality/azure-mixedreality-nspkg/azure/__init__.py new file mode 100644 index 000000000000..69e3be50dac4 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/azure/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/azure/mixedreality/__init__.py b/sdk/mixedreality/azure-mixedreality-nspkg/azure/mixedreality/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/setup.cfg b/sdk/mixedreality/azure-mixedreality-nspkg/setup.cfg new file mode 100644 index 000000000000..3480374bc2f2 --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 \ No newline at end of file diff --git a/sdk/mixedreality/azure-mixedreality-nspkg/setup.py b/sdk/mixedreality/azure-mixedreality-nspkg/setup.py new file mode 100644 index 000000000000..a80cc7d1344c --- /dev/null +++ b/sdk/mixedreality/azure-mixedreality-nspkg/setup.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from setuptools import setup + +setup( + name='azure-mixedreality-nspkg', + version='1.0.0', + description='Microsoft Azure Mixed Reality Namespace Package [Internal]', + long_description=open('README.md', 'r').read(), + license='MIT License', + author='Microsoft Corporation', + author_email='azurepysdk@microsoft.com', + url='https://github.com/Azure/azure-sdk-for-python/', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'License :: OSI Approved :: MIT License', + ], + zip_safe=False, + packages=[ + 'azure.mixedreality', + ], + install_requires=[ + 'azure-nspkg>=2.0.0', + ] +) \ No newline at end of file diff --git a/sdk/mixedreality/ci.yml b/sdk/mixedreality/ci.yml index 991d84a936a7..f3ae04fd79eb 100644 --- a/sdk/mixedreality/ci.yml +++ b/sdk/mixedreality/ci.yml @@ -28,5 +28,9 @@ extends: parameters: ServiceDirectory: mixedreality Artifacts: + - name: azure_mixedreality_nspkg + safeName: azuremixedrealitynspkg - name: azure_mgmt_mixedreality safeName: azuremgmtmixedreality + - name: azure_mixedreality_authentication + safeName: azuremixedrealityauthentication diff --git a/sdk/mixedreality/test-resources.json b/sdk/mixedreality/test-resources.json new file mode 100644 index 000000000000..30e81531cdfd --- /dev/null +++ b/sdk/mixedreality/test-resources.json @@ -0,0 +1,141 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "The base resource name." + } + }, + "tenantId": { + "type": "string", + "defaultValue": "72f988bf-86f1-41af-91ab-2d7cd011db47", + "metadata": { + "description": "The tenant ID to which the application and resources belong." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of the resource. By default, this is the same as the resource group." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('u')]" + } + }, + "variables": { + "apiVersion": "2020-05-01", + "asaAccountName": "[concat(parameters('baseName'), '-asa-account')]", + "arrApiVersion": "2020-04-06-preview", + "arrAccountName": "[concat(parameters('baseName'), '-arr-account')]", + "storageApiVersion": "2019-06-01", + "storageAccountName": "[parameters('baseName')]", + "blobContainerName": "test", + "blobContainerResourceName": "[concat(variables('storageAccountName'), '/default/', variables('blobContainerName'))]", + "sasProperties": { + "signedPermission": "rwl", + "signedExpiry": "[dateTimeAdd(parameters('baseTime'), 'P1D')]", + "signedResource": "c", + "canonicalizedResource": "[concat('/blob/', variables('storageAccountName'), '/', variables('blobContainerName'))]" + } + }, + "resources": [ + { + "type": "Microsoft.MixedReality/spatialAnchorsAccounts", + "name": "[variables('asaAccountName')]", + "apiVersion": "[variables('apiVersion')]", + "location": "[parameters('location')]", + "properties": {} + }, + { + "type": "Microsoft.MixedReality/remoteRenderingAccounts", + "name": "[variables('arrAccountName')]", + "apiVersion": "[variables('arrApiVersion')]", + "location": "[parameters('location')]", + "properties": {}, + "identity": { "type": "systemAssigned" } + }, + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "[variables('storageApiVersion')]", + "name": "[variables('storageAccountName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_RAGRS", + "tier": "Standard" + }, + "kind": "StorageV2", + "properties": { + "supportsHttpsTrafficOnly": true, + "encryption": { + "keySource": "Microsoft.Storage", + "services": { + "blob": { + "enabled": true + } + }, + }, + "accessTier": "Hot" + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "[variables('storageApiVersion')]", + "name": "[variables('blobContainerResourceName')]", + "dependsOn": [ + "[variables('storageAccountName')]" + ] + } + ], + "outputs": { + "MIXEDREALITY_ACCOUNT_ID": { + "type": "string", + "value": "[reference(variables('asaAccountName')).accountId]" + }, + "MIXEDREALITY_ACCOUNT_DOMAIN": { + "type": "string", + "value": "[reference(variables('asaAccountName')).accountDomain]" + }, + "MIXEDREALITY_ACCOUNT_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.MixedReality/spatialAnchorsAccounts', variables('asaAccountName')), variables('apiVersion')).primaryKey]" + }, + "MIXEDREALITY_ARR_ACCOUNT_ID": { + "type": "string", + "value": "[reference(variables('arrAccountName')).accountId]" + }, + "MIXEDREALITY_ARR_ACCOUNT_DOMAIN": { + "type": "string", + "value": "[reference(variables('arrAccountName')).accountDomain]" + }, + "MIXEDREALITY_ARR_ACCOUNT_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.MixedReality/remoteRenderingAccounts', variables('arrAccountName')), variables('arrApiVersion')).primaryKey]" + }, + "MIXEDREALITY_ARR_STORAGE_ACCOUNT_NAME": { + "type": "string", + "value": "[variables('storageAccountName')]" + }, + "MIXEDREALITY_ARR_STORAGE_ACCOUNT_KEY": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), variables('storageApiVersion')).keys[0].value]" + }, + "MIXEDREALITY_ARR_BLOB_CONTAINER_NAME": { + "type": "string", + "value": "[variables('blobContainerName')]" + }, + "MIXEDREALITY_ARR_SAS_TOKEN": { + "type": "string", + "value": "[listServiceSas(variables('storageAccountName'), variables('storageApiVersion'), variables('sasProperties')).serviceSasToken]" + }, + "MIXEDREALITY_ARR_SERVICE_ENDPOINT": { + "type": "string", + "value": "[concat('https://remoterendering.', parameters('location'), '.mixedreality.azure.com')]" + } + } +} \ No newline at end of file diff --git a/sdk/mixedreality/tests.yml b/sdk/mixedreality/tests.yml new file mode 100644 index 000000000000..8755e0615f27 --- /dev/null +++ b/sdk/mixedreality/tests.yml @@ -0,0 +1,13 @@ +trigger: none + +stages: + - template: ../../eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + AllocateResourceGroup: false + ServiceDirectory: mixedreality + DeployArmTemplate: true + EnvVars: + AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id) + AZURE_CLIENT_SECRET: $(aad-azure-sdk-test-client-secret) + AZURE_TENANT_ID: $(aad-azure-sdk-test-tenant-id) + TEST_MODE: 'RunLiveNoRecord' \ No newline at end of file diff --git a/shared_requirements.txt b/shared_requirements.txt index 37e9dbf4621d..a9cffd7596bc 100644 --- a/shared_requirements.txt +++ b/shared_requirements.txt @@ -84,6 +84,7 @@ azure-mgmt-storage~=2.0 azure-mgmt-subscription~=0.2.0 azure-mgmt-trafficmanager~=0.50.0 azure-mgmt-web~=0.35.0 +azure-mixedreality-nspkg azure-nspkg azure-keyvault-nspkg azure-media-nspkg