Azure / AzureAuth

R package for OAuth 2.0 authentication with Azure Active Directory
Other
42 stars 15 forks source link

Authorization_code example not working #29

Closed petros-d closed 4 years ago

petros-d commented 4 years ago

I'm tryng to setup an R Shiny app with Azure AD for authn and authz.

I can't seem to get the example working based off either this blog or the Shiny vignette.

Leaving the resource set to https://management.azure.com gives an access denied error:

[INF]: Connection opened. http://localhost:5000/?error=access_denied&error_description=AADSTS650057%3a+Invalid+resource.+The+client+has+requested+access+to+a+resource+which+is+not+listed+in+the+requested+permissions+in+the+client%27s+application+registration.+Client+app+ID%3a+xxxxxxxx-ef19-4bd3-9e13-xxxxxxxxxx(OAuth2).+Resource+value+from+request%3a+https%3a%2f%2fmanagement.azure.com.+Resource+app+ID%3a+xxxxxxx-ba00-4fd7-ba43-dac1f8f63013.+List+of+valid+resources+from+app+registration%3a+00000003-0000-0000-c000-000000000000.%0d%0aTrace+ID%3a+f63ead02-9a20-49fe-b517-09fbf55f2c00%0d%0aCorrelation+ID%3a+77214e5e-06d1-4729-99ef-39a6444e473b%0d%0aTimestamp%3a+2020-05-14+22%3a31%3a48Z&state=epkoefmtuziubrakmevu

Once the resource was changed to https://graph.microsoft.com/, I get an error stating "_The request body must contain the following parameter: 'client_assertion' or 'clientsecret'", full output below:

PS C:\Users\Petros\Desktop\azuread-rshiny> docker run --name=rshiny-azuread --user shiny --rm -p 5000:3838 azuread/rshiny 

*** warning - no files are being watched ***
[2020-05-14T21:55:21.977] [INFO] shiny-server - Shiny Server v1.5.13.944 (Node.js v12.15.0)
[2020-05-14T21:55:21.980] [INFO] shiny-server - Using config file "/etc/shiny-server/shiny-server.conf"
[2020-05-14T21:55:22.062] [INFO] shiny-server - Starting listener on http://[::]:3838

*** '/var/log/shiny-server//shiny-server-shiny-20200514-215527-42209.log' has been created ***

*** /var/log/shiny-server//shiny-server-shiny-20200514-215527-42209.log ***

Listening on http://127.0.0.1:42209
Warning: No path supplied for scope https://graph.microsoft.com/; setting to /.default
Warning: Error in process_aad_response: Unauthorized (HTTP 401). Failed to obtain Azure Active Directory token. Message:
AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Trace ID: f6181e23-5f19-4883-b8b4-e0f239d01d00
Warning: No path supplied for scope https://graph.microsoft.com/; setting to /.default
Warning: Error in process_aad_response: Unauthorized (HTTP 401). Failed to obtain Azure Active Directory token. Message:
AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Trace ID: f6181e23-5f19-4883-b8b4-e0f239d01d00
Correlation ID: 12a3cc84-fe3a-4d27-9056-765339c33442
Timestamp: 2020-05-14 21:55:35Z.
  58: <Anonymous>
Error in process_aad_response(res) :
  Unauthorized (HTTP 401). Failed to obtain Azure Active Directory token. Message:
AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Trace ID: f6181e23-5f19-4883-b8b4-e0f239d01d00
Correlation ID: 12a3cc84-fe3a-4d27-9056-765339c33442
Timestamp: 2020-05-14 21:55:35Z.

Adding the password field to get_azure_token() gets rid of the error, but uses the client_credential authentication flow:

token <- get_azure_token(c("https://graph.microsoft.com/"),tenant,password="/zY.uiYOAxxxxxxxxxxVP",
                        app,version=2,authorize_args=list(redirect_uri="http://localhost:5000"),use_cache=FALSE, 
                        auth_code=params$code)

The output for this is below:

PS C:\Users\Petros\Desktop\azuread-rshiny> docker run --name=rshiny-azuread --user shiny --rm -p 5000:3838 azuread/rshiny 
*** warning - no files are being watched ***
[2020-05-14T21:38:02.608] [INFO] shiny-server - Shiny Server v1.5.13.944 (Node.js v12.15.0)
[2020-05-14T21:38:02.611] [INFO] shiny-server - Using config file "/etc/shiny-server/shiny-server.conf"
[2020-05-14T21:38:02.692] [INFO] shiny-server - Starting listener on http://[::]:3838

*** '/var/log/shiny-server//shiny-server-shiny-20200514-213809-43161.log' has been created ***

*** /var/log/shiny-server//shiny-server-shiny-20200514-213809-43161.log ***

Listening on http://127.0.0.1:43161
Using client_credentials flow
Warning: No path supplied for scope https://graph.microsoft.com/; setting to /.default

However I would like the users OpenID token for authz, which I believe is not compatible with the client_credentials flow. Are the examples provided in the vignette and the blog still accurate?

The code I am running is available in my repo here: https://github.com/petros-d/AzureAD-RShiny/blob/master/shinyapps/app.r

Note the example is running in a docker container with only a single port exposed. The logs make reference to the application listening on random high ports (Listening on http://127.0.0.1:43161) when trying to use the authorization_code flow. Are these ports being accessible externally a requirement for this auth type?

petros-d commented 4 years ago

FYI I've seen issue #18 with the same error, but I believe my app has been setup in Azure AD correctly (as a public client, though I've tried both):

image

hongooi73 commented 4 years ago

The vignette works fine, but makes a couple of implicit assumptions:

get_azure_token has an auth_type argument that sets which authentication flow to use. If you don't specify this, it tries to guess based on the other arguments supplied. In your case, since you have a client secret, you want to specify auth_type="authorization_code" to override the default.

The resource argument for the token is meant to contain whatever Azure resource you want access to: storage, database, Kusto, etc. Since you're changing this argument at will, it looks like you don't actually have any resources that require authorization and you're only using AAD for authentication. In this case, obtaining an AADv2 token with resource="openid" is the way to go.

get_azure_token(resource="openid", tenant, password="xxx", app, 
    auth_type="authorization_code", version=2, use_cache=FALSE,
    authorize_args=list(redirect_uri="http://localhost:5000"), auth_code=params$code)
hongooi73 commented 4 years ago

Example of native (aka "mobile and desktop") redirects in the AAD/registered app/authentication pane in the portal:

image

Example of web redirect:

image

petros-d commented 4 years ago

Thank you for providing the example of a native (aka "mobile and desktop") redirect in the Azure Portal. After configuring my app registration to use that, the application now successfully gets the access token and is able to decode it with decode_jwt().

Out of interest, I am attempting to configure App Roles as fields in the token following the documentation here but am not seeing the roles appear in the access token. When attempting to simulate the same process with Postman, I'm seeing the same issue with the access token not containing the roles, however I do also get an id_token, which does contain the roles.

Is there a way to use AzureAuth to retrieve and access the id_token as well?

hongooi73 commented 4 years ago

See the front page of the repo or the intro vignette. The ID token can be obtained with extract_jwt(token, "id") and decode_jwt(token, "id").

I'm not an expert on configuring AAD roles; you may want to ask your local IT people or maybe on StackOverflow. In the meantime, since AzureAuth seems to be working, I'm closing this. Let me know if you run into other problems with the package.