def _azure_interactive_auth(self): if self._authentication_record_json is None: _interactive_credential = DeviceCodeCredential( tenant_id=self._tenant_id, timeout=180, prompt_callback=None, _cache=load_persistent_cache( TokenCachePersistenceOptions( name=self._azure_cred_cache_name, allow_unencrypted_storage=True, cache_location=self._azure_cred_cache_location))) _auth_record = _interactive_credential.authenticate() self._authentication_record_json = _auth_record.serialize() else: deserialized_auth_record = AuthenticationRecord.deserialize( self._authentication_record_json) _interactive_credential = DeviceCodeCredential( tenant_id=self._tenant_id, timeout=180, prompt_callback=None, _cache=load_persistent_cache( TokenCachePersistenceOptions( name=self._azure_cred_cache_name, allow_unencrypted_storage=True, cache_location=self._azure_cred_cache_location)), authentication_record=deserialized_auth_record) return _interactive_credential
def test_policies_configurable(): policy = Mock(spec_set=SansIOHTTPPolicy, on_request=Mock()) transport = validating_transport( requests=[Request()] * 3, responses=[ # expected requests: discover tenant, start device code flow, poll for completion get_discovery_response(), mock_response( json_payload={ "device_code": "_", "user_code": "user-code", "verification_uri": "verification-uri", "expires_in": 42, } ), mock_response(json_payload=dict(build_aad_response(access_token="**"), scope="scope")), ], ) credential = DeviceCodeCredential( client_id="client-id", prompt_callback=Mock(), policies=[policy], transport=transport ) credential.get_token("scope") assert policy.on_request.called
def test_user_agent(): client_id = "client-id" transport = validating_transport( requests=[Request()] * 2 + [Request(required_headers={"User-Agent": USER_AGENT})], responses=[ get_discovery_response(), mock_response( json_payload={ "device_code": "_", "user_code": "user-code", "verification_uri": "verification-uri", "expires_in": 42, }), mock_response(json_payload=dict(build_aad_response( access_token="**", id_token=build_id_token(aud=client_id)), scope="scope")), ], ) credential = DeviceCodeCredential(client_id=client_id, prompt_callback=Mock(), transport=transport) credential.get_token("scope")
def test_device_code_credential_timeout(): transport = validating_transport( requests=[Request()] * 3, # not validating requests because they're formed by MSAL responses=[ # expected requests: discover tenant, start device code flow, poll for completion mock_response( json_payload={ "authorization_endpoint": "https://a/b", "token_endpoint": "https://a/b" }), mock_response(json_payload={ "device_code": "_", "user_code": "_", "verification_uri": "_" }), mock_response(json_payload={"error": "authorization_pending"}), ], ) credential = DeviceCodeCredential(client_id="_", prompt_callback=Mock(), transport=transport, timeout=0.01, instance_discovery=False) with pytest.raises(ClientAuthenticationError) as ex: credential.get_token("scope") assert "timed out" in ex.value.message.lower()
def test_device_code_credential(): client_id = "client-id" expected_token = "access-token" user_code = "user-code" verification_uri = "verification-uri" expires_in = 42 transport = validating_transport( requests=[Request()] * 3, # not validating requests because they're formed by MSAL responses=[ # expected requests: discover tenant, start device code flow, poll for completion mock_response( json_payload={ "authorization_endpoint": "https://a/b", "token_endpoint": "https://a/b" }), mock_response( json_payload={ "device_code": "_", "user_code": user_code, "verification_uri": verification_uri, "expires_in": expires_in, }), mock_response(json_payload=dict( build_aad_response( access_token=expected_token, expires_in=expires_in, refresh_token="_", id_token=build_id_token(aud=client_id), ), scope="scope", ), ), ], ) callback = Mock() credential = DeviceCodeCredential( client_id=client_id, prompt_callback=callback, transport=transport, instance_discovery=False, _cache=TokenCache(), ) now = datetime.datetime.utcnow() token = credential.get_token("scope") assert token.token == expected_token # prompt_callback should have been called as documented assert callback.call_count == 1 uri, code, expires_on = callback.call_args[0] assert uri == verification_uri assert code == user_code # validating expires_on exactly would require depending on internals of the credential and # patching time, so we'll be satisfied if expires_on is a datetime at least expires_in # seconds later than our call to get_token assert isinstance(expires_on, datetime.datetime) assert expires_on - now >= datetime.timedelta(seconds=expires_in)
def test_authenticate(): client_id = "client-id" environment = "localhost" issuer = "https://" + environment tenant_id = "some-tenant" authority = issuer + "/" + tenant_id access_token = "***" scope = "scope" # mock AAD response with id token object_id = "object-id" home_tenant = "home-tenant-id" username = "******" id_token = build_id_token(aud=client_id, iss=issuer, object_id=object_id, tenant_id=home_tenant, username=username) auth_response = build_aad_response(uid=object_id, utid=home_tenant, access_token=access_token, refresh_token="**", id_token=id_token) transport = validating_transport( requests=[Request(url_substring=issuer)] * 4, responses=[get_discovery_response(authority)] * 2 # instance and tenant discovery + [ mock_response( # start device code flow json_payload={ "device_code": "_", "user_code": "user-code", "verification_uri": "verification-uri", "expires_in": 42, } ), mock_response(json_payload=dict(auth_response, scope=scope)), # poll for completion ], ) credential = DeviceCodeCredential( client_id, prompt_callback=Mock(), # prevent credential from printing to stdout transport=transport, authority=environment, tenant_id=tenant_id, _cache=TokenCache(), ) record = credential.authenticate(scopes=(scope, )) # credential should have a cached access token for the scope used in authenticate token = credential.get_token(scope) assert token.token == access_token assert record.authority == environment assert record.home_account_id == object_id + "." + home_tenant assert record.tenant_id == home_tenant assert record.username == username
def test_disable_automatic_authentication(): """When configured for strict silent auth, the credential should raise when silent auth fails""" transport = Mock(send=Mock(side_effect=Exception("no request should be sent"))) credential = DeviceCodeCredential("client-id", disable_automatic_authentication=True, transport=transport) with pytest.raises(AuthenticationRequiredError): credential.get_token("scope")
def test_tenant_id_validation(): """The credential should raise ValueError when given an invalid tenant_id""" valid_ids = {"c878a2ab-8ef4-413b-83a0-199afb84d7fb", "contoso.onmicrosoft.com", "organizations", "common"} for tenant in valid_ids: DeviceCodeCredential(tenant_id=tenant) invalid_ids = {"my tenant", "my_tenant", "/", "\\", '"my-tenant"', "'my-tenant'"} for tenant in invalid_ids: with pytest.raises(ValueError): DeviceCodeCredential(tenant_id=tenant)
def test_client_capabilities(): """the credential should configure MSAL for capability CP1 (ability to handle claims challenges)""" transport = Mock(send=Mock(side_effect=Exception( "this test mocks MSAL, so no request should be sent"))) credential = DeviceCodeCredential(transport=transport) with patch("msal.PublicClientApplication") as PublicClientApplication: credential._get_app() assert PublicClientApplication.call_count == 1 _, kwargs = PublicClientApplication.call_args assert kwargs["client_capabilities"] == ["CP1"]
def test_claims_challenge(): """get_token and authenticate should pass any claims challenge to MSAL token acquisition APIs""" msal_acquire_token_result = dict( build_aad_response(access_token="**", id_token=build_id_token()), id_token_claims=id_token_claims("issuer", "subject", "audience", upn="upn"), ) expected_claims = '{"access_token": {"essential": "true"}' transport = Mock(send=Mock(side_effect=Exception("this test mocks MSAL, so no request should be sent"))) credential = DeviceCodeCredential(transport=transport) with patch.object(DeviceCodeCredential, "_get_app") as get_mock_app: msal_app = get_mock_app() msal_app.initiate_device_flow.return_value = {"message": "it worked"} msal_app.acquire_token_by_device_flow.return_value = msal_acquire_token_result credential.authenticate(scopes=["scope"], claims=expected_claims) assert msal_app.acquire_token_by_device_flow.call_count == 1 args, kwargs = msal_app.acquire_token_by_device_flow.call_args assert kwargs["claims_challenge"] == expected_claims credential.get_token("scope", claims=expected_claims) assert msal_app.acquire_token_by_device_flow.call_count == 2 args, kwargs = msal_app.acquire_token_by_device_flow.call_args assert kwargs["claims_challenge"] == expected_claims msal_app.get_accounts.return_value = [{"home_account_id": credential._auth_record.home_account_id}] msal_app.acquire_token_silent_with_error.return_value = msal_acquire_token_result credential.get_token("scope", claims=expected_claims) assert msal_app.acquire_token_silent_with_error.call_count == 1 args, kwargs = msal_app.acquire_token_silent_with_error.call_args assert kwargs["claims_challenge"] == expected_claims
def __init__(self, synapse_dev_url: str, pool_name: str, datalake_dir: str, executor_size: str, executors: int): tenant_id = '72f988bf-86f1-41af-91ab-2d7cd011db47' authority_host_uri = 'login.microsoftonline.com' client_id = '04b07795-8ddb-461a-bbee-02f9e1bf7b46' global login_credential_cache # use a global cache to store the credential, to avoid users from multiple login if login_credential_cache is None: # use DeviceCodeCredential if EnvironmentCredential is not available self.credential = ChainedTokenCredential( EnvironmentCredential(), DeviceCodeCredential(client_id, authority=authority_host_uri, tenant=tenant_id)) login_credential_cache = self.credential else: self.credential = login_credential_cache self._api = SynapseJobRunner(synapse_dev_url, pool_name, executor_size=executor_size, executors=executors, credential=self.credential) self._datalake = DataLakeFiler(datalake_dir, credential=self.credential)
def test_device_code_credential(): expected_token = "access-token" user_code = "user-code" verification_uri = "verification-uri" expires_in = 42 transport = validating_transport( requests=[Request()] * 3, # not validating requests because they're formed by MSAL responses=[ # expected requests: discover tenant, start device code flow, poll for completion mock_response( json_payload={ "authorization_endpoint": "https://a/b", "token_endpoint": "https://a/b" }), mock_response( json_payload={ "device_code": "_", "user_code": user_code, "verification_uri": verification_uri, "expires_in": expires_in, }), mock_response( json_payload={ "access_token": expected_token, "expires_in": expires_in, "scope": "scope", "token_type": "Bearer", "refresh_token": "_", }), ], ) callback = Mock() credential = DeviceCodeCredential(client_id="_", prompt_callback=callback, transport=transport, instance_discovery=False) token = credential.get_token("scope") assert token.token == expected_token # prompt_callback should have been called as documented assert callback.call_count == 1 assert callback.call_args[0] == (verification_uri, user_code, expires_in)
def test_device_code(): import webbrowser def prompt(url, user_code, _): print("opening a browser to '{}', enter device code {}".format(url, user_code)) webbrowser.open_new_tab(url) credential = DeviceCodeCredential(client_id=AZURE_CLI_CLIENT_ID, prompt_callback=prompt, timeout=40) get_token(credential)
def test_client_capabilities(): """the credential should configure MSAL for capability CP1 unless AZURE_IDENTITY_DISABLE_CP1 is set""" transport = Mock(send=Mock(side_effect=Exception("this test mocks MSAL, so no request should be sent"))) with patch("msal.PublicClientApplication") as PublicClientApplication: DeviceCodeCredential(transport=transport)._get_app() assert PublicClientApplication.call_count == 1 _, kwargs = PublicClientApplication.call_args assert kwargs["client_capabilities"] == ["CP1"] with patch.dict("os.environ", {"AZURE_IDENTITY_DISABLE_CP1": "true"}): with patch("msal.PublicClientApplication") as PublicClientApplication: DeviceCodeCredential(transport=transport)._get_app() assert PublicClientApplication.call_count == 1 _, kwargs = PublicClientApplication.call_args assert kwargs["client_capabilities"] is None
def test_tenant_id(): client_id = "client-id" expected_token = "access-token" user_code = "user-code" verification_uri = "verification-uri" expires_in = 42 transport = validating_transport( requests=[Request()] * 3, # not validating requests because they're formed by MSAL responses=[ # expected requests: discover tenant, start device code flow, poll for completion mock_response(json_payload={"authorization_endpoint": "https://a/b", "token_endpoint": "https://a/b"}), mock_response( json_payload={ "device_code": "_", "user_code": user_code, "verification_uri": verification_uri, "expires_in": expires_in, } ), mock_response( json_payload=dict( build_aad_response( access_token=expected_token, expires_in=expires_in, refresh_token="_", id_token=build_id_token(aud=client_id), ), scope="scope", ), ), ], ) callback = Mock() credential = DeviceCodeCredential( client_id=client_id, prompt_callback=callback, transport=transport, instance_discovery=False, ) now = datetime.datetime.utcnow() token = credential.get_token("scope", tenant_id="tenant_id") assert token.token == expected_token
def _initialize_credentials(self): if self.subscription_id is not None \ and self.arm_base_url is not None: if self.vscode_tenant_id is None: self.vscode_tenant_id = self._get_tenant_id( arm_base_url=self.arm_base_url, subscription_id=self.subscription_id) if self.shared_cache_tenant_id is None: self.shared_cache_tenant_id = self._get_tenant_id( arm_base_url=self.arm_base_url, subscription_id=self.subscription_id) if self.interactive_browser_tenant_id is None: self.interactive_browser_tenant_id = self._get_tenant_id( arm_base_url=self.arm_base_url, subscription_id=self.subscription_id) credentials = [] # type: List[AsyncTokenCredential] if not self.exclude_token_file_credential: credentials.append(_TokenFileCredential()) if not self.exclude_environment_credential: credentials.append(EnvironmentCredential(authority=self.authority)) if not self.exclude_managed_identity_credential: credentials.append( ManagedIdentityCredential( client_id=self.managed_identity_client_id)) if not self.exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported( ): try: # username and/or tenant_id are only required when the cache contains tokens for multiple identities shared_cache = SharedTokenCacheCredential( username=self.shared_cache_username, tenant_id=self.shared_cache_tenant_id, authority=self.authority) credentials.append(shared_cache) except Exception as ex: # pylint:disable=broad-except _LOGGER.info("Shared token cache is unavailable: '%s'", ex) if not self.exclude_visual_studio_code_credential: credentials.append( VisualStudioCodeCredential(tenant_id=self.vscode_tenant_id)) if not self.exclude_cli_credential: credentials.append(AzureCliCredential()) if not self.exclude_powershell_credential: credentials.append(AzurePowerShellCredential()) if not self.exclude_interactive_browser_credential: credentials.append( InteractiveBrowserCredential( tenant_id=self.interactive_browser_tenant_id)) if not self.exclude_device_code_credential: credentials.append( DeviceCodeCredential( tenant_id=self.interactive_browser_tenant_id)) self.credentials = credentials
def _get_secret_client(self): if self.authn_type == "device": authority = self.authority_uri.replace("https://", "") credentials = DeviceCodeCredential( client_id=self.settings.CLIENT_ID, authority=authority, prompt_callback=_device_code_callback, ) else: credentials = InteractiveBrowserCredential() # Create a secret client secret_client = SecretClient(self.vault_uri, credentials) return secret_client
def __init__(self, scheduler: HistoricNetworkScheduler): self.scheduler = scheduler self.subscribed_instruments = MutableSignal() self.scheduler.get_network().attach(self.subscribed_instruments) self.start_time = scheduler.get_clock().get_start_time() self.end_time = scheduler.get_clock().get_end_time() self.all_subscribed = set() self.book_signal_by_symbol = {} self.trade_signal_by_symbol = {} self.credential = DeviceCodeCredential(client_id=get_global_defaults()['azure']['client_id'], tenant_id=get_global_defaults()['azure']['tenant_id'])
def _generate_credential(auth_method: str, token_path: Path, **kwargs): if auth_method == AuthMethod.DeviceCode.name: credential = DeviceCodeCredential( client_id=kwargs['client_id'], client_secret=kwargs['client_secret'], disable_automatic_authentication=True, tenant_id=kwargs['tenant_id'], **_get_cache_args(token_path)) elif auth_method == AuthMethod.UsernamePassword.name: credential = UsernamePasswordCredential( client_id=kwargs['client_id'], client_credential=kwargs['client_secret'], disable_automatic_authentication=True, username=kwargs['username'], password=kwargs['password'], **_get_cache_args(token_path)) elif auth_method == AuthMethod.ClientSecret.name: credential = ClientSecretCredential( client_id=kwargs['client_id'], tenant_id=kwargs['tenant_id'], client_secret=kwargs['client_secret']) else: raise RuntimeError(f'Auth method {auth_method} not found') return credential
# # 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. # -------------------------------------------------------------------------------------------- from azure.identity import DeviceCodeCredential from azure.mgmt.resource import SubscriptionClient from azure.mgmt.resource import ResourceManagementClient credential = DeviceCodeCredential() subscription_client = SubscriptionClient(credential) sub_list = subscription_client.subscriptions.list() for sub in sub_list: print("Displaying resources in subscription ID:", sub.subscription_id) resource_client = ResourceManagementClient(credential, sub.subscription_id) res_list = resource_client.resources.list() for res in res_list: print() print("Resource:", res.id) print("\tLocation:", res.location) print("\tProperties:", res.properties)
def test_device_code(self): credential = DeviceCodeCredential( authority=self.cae_settings["authority"], tenant_id=self.cae_settings["tenant_id"]) self.cae_test(credential)
def _get_creds_from_login(self, authentication, reason=None): # use normal Key Value from azure.keyvault.secrets import SecretClient if authentication == "auto": authentication = "browser" if pc_utils.has_gui() else "device-code" if authentication == "browser": console.print("authenticating with azure thru browser... ", flush=True, end="") from azure.identity import InteractiveBrowserCredential if self.azure_tenant_id is not None: credential = InteractiveBrowserCredential( tenant_id=self.azure_tenant_id) else: credential = InteractiveBrowserCredential() elif authentication == "device-code": # console.print("authenticating with azure thru device code... ", flush=True, end="") from azure.identity import DeviceCodeCredential from azure.identity._constants import AZURE_CLI_CLIENT_ID console.print( "using device-code authorization (Azure AD currently requires 2-4 authenications here)" ) if self.azure_tenant_id is not None: credential = DeviceCodeCredential( tenant_id=self.azure_tenant_id, client_id=AZURE_CLI_CLIENT_ID) else: credential = DeviceCodeCredential( client_id=AZURE_CLI_CLIENT_ID) else: errors.syntax_error( "unrecognized authentication type '{}'".format(authentication)) new_creds = True outer_token = credential.get_token() token = outer_token.token # expires = outer_token[1] # elapsed = expires - time.time() #print(" [new token expires in {:.2f} mins] ".format(elapsed/60), end="") # get keys from keyvault self.client = SecretClient(self.vault_url, credential=credential) key_text = self.get_secret_live("xt-keys") console.print("authenticated successfully", flush=True) #xt_client_cert = self.get_secret_live("xt-clientcert") xt_server_cert = self.get_secret_live("xt-servercert") # write all our creds to self.keys self.apply_creds(key_text) self.keys["xt_server_cert"] = xt_server_cert self.keys["object_id"] = self.get_me_graph_property(token, "id") # return creds as json string return json.dumps(self.keys)
def test_no_scopes(): """The credential should raise when get_token is called with no scopes""" credential = DeviceCodeCredential("client_id") with pytest.raises(ValueError): credential.get_token()
from azure.identity import DeviceCodeCredential from msgraphcore import GraphSession import os, json # Keep secrets/config in .env file from dotenv import load_dotenv load_dotenv() # Graph API scopes we need scopes = ['User.Read', 'User.ReadBasic.All'] # Use device code flow as we're a console app # Set CLIENT_ID in .env file before running browser_credential = DeviceCodeCredential(client_id=os.environ['CLIENT_ID']) graph_session = GraphSession(browser_credential, scopes) # User search term searchString="Ben C" # Call graph with a search for users result = graph_session.get(f"/users?$filter=startswith(displayName, '{searchString}') or startswith(userPrincipalName, '{searchString}')") # Just dump JSON to stdout, obviously a real app would do something less dumb print(json.dumps(result.json(), indent=2))