microsoft / teams-ai

SDK focused on building AI based applications and extensions for Microsoft Teams and other Bot Framework channels
MIT License
403 stars 176 forks source link

[Dev support]: Python Single Tenant Application SSO #2051

Closed beathvn closed 22 hours ago

beathvn commented 5 days ago

Question

hi there,

i have implemented a basic ai chatbot with sso, as in the sample oauthbot. the only thing i have changed is that i have deployed it as a docker container to azure docker container apps instead of the azure app service (i did then also change the messaging endpoint for the bot resource, for it to be correct) - and my setup works fine: I do get it up and running.

BUT: since i want my teams app to be available just for users inside my tenant, i want to have the application to be of type AzureADMyOrg and not of type AzureADMultipleOrgs.

The problem is, that once i change the application to be AzureADMyOrg, it doesn't work anymore, giving me this error (with xxxxxxxx being my actual app_id, which i verfied and is correct):

PermissionError: Failed to get access token with error: unauthorized_client, error_description: AADSTS700016: Application with identifier 'xxxxxxxx' was not found in the directory 'Bot Framework'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.

I have setup the application following this guide, except that i have selected single tenant instead of multi tenant.

The Azure Bot Service Resource is setup with the sso connection (with tenant_id set to my tenant_id) and the test connection button confirms the correct functioning of that connection.

Any ideas, of where it goes wrong?

Code snippets

N/A

What you have tried already

every of the following attempts didn't change the behaviour:

from dotenv import load_dotenv

load_dotenv()

class Config: PORT = 3978 APP_ID = os.environ.get("BOT_ID", "") APP_PASSWORD = os.environ.get("BOT_PASSWORD", "") AZURE_OPENAI_API_KEY = os.environ["AZURE_OPENAI_API_KEY"] # Azure OpenAI API key AZURE_OPENAI_MODEL_DEPLOYMENT_NAME = os.environ["AZURE_OPENAI_MODEL_DEPLOYMENT_NAME"] # Azure OpenAI model deployment name AZURE_OPENAI_ENDPOINT = os.environ["AZURE_OPENAI_ENDPOINT"] # Azure OpenAI endpoint OAUTH_CONNECTION_NAME = os.environ["OAUTH_CONNECTION_NAME"] MicrosoftAppType = "SingleTenant" MicrosoftAppId = APP_ID MicrosoftAppPassword = APP_PASSWORD MicrosoftAppTenantId = os.environ["TENANT_ID"]

corinagum commented 4 days ago

@beathvn when setting up Azure Bot Service, did you originally pick Multi-tenant? When you changed the AAD app to single tenant, did you also update your ABS to single tenant in Azure portal?

corinagum commented 4 days ago

also @beathvn could you confirm whether your config is using AAD_APP_TENANT_ID or TENANT_ID? Your code snippet for config says TENANT_ID so I wanted to double check.

image

To answer this question:

I tried adding additional environmental variables to the container app, since the oauth sample exports them (but doesn't use them if i am not mistaken?) AAD_APP_OBJECT_ID, AAD_APP_TENANT_ID,

If you do not pre-fill the env variables, TTK will automatically provision and fill out these values for you (in a correctly working scenario). Do you by chance recall if they were auto-provisioned when you first initialized (before trying to change to single tenant)? If values like Bot ID/Password or tenant information (values not related to Azure/OpenAI) are prefilled, the yml file will skip the provisioning step.

One thing you could check out -- TTK has their own sample that uses 2 AAD apps instead of 1 so that ABS doesn't need to be modified if switching to single tenant. If you have a chance, could you give that a go? It's TS, not PY, so it won't be a final solution for you but might be helpful pinning down the issue.

image
beathvn commented 3 days ago

Thanks for the quick answer!

I am using AAD_APP_TENANT_ID sorry - just sent an old code snippet (i even tried to hardcode the values) to be sure. I connected to the azure container app with a console and checked the values with printenv - but the values are correct, i double checked that.

Yes I let the values to be autocompleted, but i double checked, that they are linked to the correct app id and password (the single tenant one)

hmm... yes i had a look at it, tried adding all of the parameters that are in the config.ts, made sure that the values are correct, but it didn't change the outcome. Any other idea?

I tried following this tutorial for app configuration and tried adding the suggested redirect uri (https://login.microsoftonline.com//oauth2/v2.0/token) - without changing the result though

corinagum commented 3 days ago

Thanks for confirming!

Regarding this part of your comment:

hmm... yes i had a look at it, tried adding all of the parameters that are in the config.ts, made sure that the values are correct, but it didn't change the outcome. Any other idea?

Is this in regard to the TTK sample I pointed out? Did you run that sample and come across the same issues? If yes, this implies to me that there's something going on behind the scenes with the tenant settings. If no, could you try running that sample (separately from your current oauth code) and let me know your results?

Would you be able to temporarily put up a github repo that has the oauth bot configured with docker? It would be a great help -- we can try to reproduce the same scenario on a different tenant. Please make sure no PII or keys/IDs/Passwords are checked in.

beathvn commented 22 hours ago

hi there, i did some digging in the source code of the teams_adapter and the botbuilder and figured out the problem I was facing:

the bot app is created like this (according to the oauthbot sample):

app = Application[TurnState[ConversationState, UserState, TempState]](
    ApplicationOptions(
        bot_app_id=config.APP_ID,
        storage=MemoryStorage(),
        adapter=TeamsAdapter(config),
        auth=AuthOptions(
            default="graph",
            auto=True,
            settings={
                "graph": OAuthOptions(
                    connection_name=config.OAUTH_CONNECTION_NAME,
                    title="Sign In",
                    text="please sign in",
                    end_on_invalid_message=True,
                    enable_sso=True,
                ),
            },
        ),
    )
)

and as an adapter the TeamsAdapter class is passed. That one creates a ConfigurationServiceClientCredentialFactory object to handle authentification (if nothing is passed for the optional credentials_factory parameter, which is the case here). There it looks for config parameters named APP_TYPE and APP_TENANTID, whereas these docs suggest to set MicrosoftAppType, MicrosoftAppId, MicrosoftAppPassword, MicrosoftAppTenantId

Once I added the parameters APP_TYPE and APP_TENANTID to the config class, everything worked as expected also for the single tenant application.