Skip to content

[Core] az logout: Remove service principal access tokens from token cache - #29441

Merged
Jiashuo Li (jiasli) merged 1 commit into
Azure:devfrom
jiasli:logout-sp
Jul 26, 2024
Merged

[Core] az logout: Remove service principal access tokens from token cache#29441
Jiashuo Li (jiasli) merged 1 commit into
Azure:devfrom
jiasli:logout-sp

Conversation

@jiasli

@jiasli Jiashuo Li (jiasli) commented Jul 22, 2024

Copy link
Copy Markdown
Contributor

Related command
az logout

Description
Based on AzureAD/microsoft-authentication-library-for-python#666 from MSAL 1.27.0 (adopted by #28556).

Testing Guide

# Disable token cache encryption so that we can directly check the content of ~/.azure/msal_token_cache.json
az config set core.encrypt_token_cache=false

az login --service-principal --username xxx --password xxx --tenant xxx
# Log out current account
az logout

az login --service-principal --username xxx --password xxx --tenant xxx
# Log out by SP client ID
az logout --username xxx

@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Jul 22, 2024

Copy link
Copy Markdown
️✔️AzureCLI-FullTest
️✔️acr
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️acs
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️advisor
️✔️latest
️✔️3.11
️✔️3.9
️✔️ams
️✔️latest
️✔️3.11
️✔️3.9
️✔️apim
️✔️latest
️✔️3.11
️✔️3.9
️✔️appconfig
️✔️latest
️✔️3.11
️✔️3.9
️✔️appservice
️✔️latest
️✔️3.11
️✔️3.9
️✔️aro
️✔️latest
️✔️3.11
️✔️3.9
️✔️backup
️✔️latest
️✔️3.11
️✔️3.9
️✔️batch
️✔️latest
️✔️3.11
️✔️3.9
️✔️batchai
️✔️latest
️✔️3.11
️✔️3.9
️✔️billing
️✔️latest
️✔️3.11
️✔️3.9
️✔️botservice
️✔️latest
️✔️3.11
️✔️3.9
️✔️cdn
️✔️latest
️✔️3.11
️✔️3.9
️✔️cloud
️✔️latest
️✔️3.11
️✔️3.9
️✔️cognitiveservices
️✔️latest
️✔️3.11
️✔️3.9
️✔️compute_recommender
️✔️latest
️✔️3.11
️✔️3.9
️✔️config
️✔️latest
️✔️3.11
️✔️3.9
️✔️configure
️✔️latest
️✔️3.11
️✔️3.9
️✔️consumption
️✔️latest
️✔️3.11
️✔️3.9
️✔️container
️✔️latest
️✔️3.11
️✔️3.9
️✔️containerapp
️✔️latest
️✔️3.11
️✔️3.9
️✔️core
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️cosmosdb
️✔️latest
️✔️3.11
️✔️3.9
️✔️databoxedge
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️dla
️✔️latest
️✔️3.11
️✔️3.9
️✔️dls
️✔️latest
️✔️3.11
️✔️3.9
️✔️dms
️✔️latest
️✔️3.11
️✔️3.9
️✔️eventgrid
️✔️latest
️✔️3.11
️✔️3.9
️✔️eventhubs
️✔️latest
️✔️3.11
️✔️3.9
️✔️feedback
️✔️latest
️✔️3.11
️✔️3.9
️✔️find
️✔️latest
️✔️3.11
️✔️3.9
️✔️hdinsight
️✔️latest
️✔️3.11
️✔️3.9
️✔️identity
️✔️latest
️✔️3.11
️✔️3.9
️✔️iot
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️keyvault
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️kusto
️✔️latest
️✔️3.11
️✔️3.9
️✔️lab
️✔️latest
️✔️3.11
️✔️3.9
️✔️managedservices
️✔️latest
️✔️3.11
️✔️3.9
️✔️maps
️✔️latest
️✔️3.11
️✔️3.9
️✔️marketplaceordering
️✔️latest
️✔️3.11
️✔️3.9
️✔️monitor
️✔️latest
️✔️3.11
️✔️3.9
️✔️mysql
️✔️latest
️✔️3.11
️✔️3.9
️✔️netappfiles
️✔️latest
️✔️3.11
️✔️3.9
️✔️network
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️policyinsights
️✔️latest
️✔️3.11
️✔️3.9
️✔️privatedns
️✔️latest
️✔️3.11
️✔️3.9
️✔️profile
️✔️latest
️✔️3.11
️✔️3.9
️✔️rdbms
️✔️latest
️✔️3.11
️✔️3.9
️✔️redis
️✔️latest
️✔️3.11
️✔️3.9
️✔️relay
️✔️latest
️✔️3.11
️✔️3.9
️✔️resource
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️role
️✔️latest
️✔️3.11
️✔️3.9
️✔️search
️✔️latest
️✔️3.11
️✔️3.9
️✔️security
️✔️latest
️✔️3.11
️✔️3.9
️✔️servicebus
️✔️latest
️✔️3.11
️✔️3.9
️✔️serviceconnector
️✔️latest
️✔️3.11
️✔️3.9
️✔️servicefabric
️✔️latest
️✔️3.11
️✔️3.9
️✔️signalr
️✔️latest
️✔️3.11
️✔️3.9
️✔️sql
️✔️latest
️✔️3.11
️✔️3.9
️✔️sqlvm
️✔️latest
️✔️3.11
️✔️3.9
️✔️storage
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️synapse
️✔️latest
️✔️3.11
️✔️3.9
️✔️telemetry
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9
️✔️util
️✔️latest
️✔️3.11
️✔️3.9
️✔️vm
️✔️2018-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.11
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.11
️✔️3.9
️✔️latest
️✔️3.11
️✔️3.9

@azure-client-tools-bot-prd

Copy link
Copy Markdown

Hi Jiashuo Li (@jiasli),
Since the current milestone time is less than 7 days, this pr will be reviewed in the next milestone.

@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Jul 22, 2024

Copy link
Copy Markdown
️✔️AzureCLI-BreakingChangeTest
️✔️Non Breaking Changes

@yonzhan

Copy link
Copy Markdown
Collaborator

Core

Comment on lines +235 to +236
# TODO: As MSAL provides no interface to get all service principals in its token cache, this method can't
# clear all service principals' access tokens from MSAL token cache.

@jiasli Jiashuo Li (jiasli) Jul 22, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a comment at AzureAD/microsoft-authentication-library-for-python#666 (comment).

Luckily, when az account clear is called, it internally calls logout_all_users which deletes the whole token cache file, bypassing this issue.

Comment on lines +222 to +231
def logout_service_principal(self, client_id):
# If client_id is a username, it is ignored

# Step 1: Remove SP from MSAL token cache
# Note that removing SP access tokens shouldn't rely on SP store
cca = ConfidentialClientApplication(client_id, **self._msal_app_kwargs)
cca.remove_tokens_for_client()

# Step 2: Remove SP from SP store
self._service_principal_store.remove_entry(client_id)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally wrote the code as

    def logout_service_principal(self, client_id):
        try:
            entry = self._service_principal_store.load_entry(client_id, self.tenant_id)
        except CLIError as ex:
            logger.info('%s %s is possibly a user account.', ex, client_id)
            return

        # Step 1: Remove service principal access tokens from MSAL token cache.
        sp_auth = ServicePrincipalAuth(entry)
        cred = ServicePrincipalCredential(sp_auth, **self._msal_app_kwargs)
        cred.remove_tokens_for_client()

        # Step 2: Remove service principal secrets
        self._service_principal_store.remove_entry(client_id)

Then I realized removing an SP from token cache doesn't require client_credential, so there is no need to read from self._service_principal_store and create a fully-functioning ServicePrincipalCredential.

@jiasli

Copy link
Copy Markdown
Contributor Author

There is one edge case caused by the "subscription ID as primary key" issue (#15005). If sp1 and sp2 have access to the same subscription, after running az login for sp1, running az login for sp2 will overwrite the subscription-tenant-user login context of sp1, making CLI lose track of sp1 in its profile.

To solve that, the user must either

  • Remember sp1's client ID and use it in az login --username {sp1_client_id}
  • Run az account clear which purges the whole token cache

The same happens to user accounts too.

bebound
Hang (bebound) previously approved these changes Jul 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Account az login/account Auto-Assign Auto assign by bot Core CLI core infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants