microsoft / dev-proxy

Dev Proxy is an API simulator that helps you effortlessly test your app beyond the happy path.
https://aka.ms/devproxy
MIT License
496 stars 58 forks source link

[BUG]: AzureCliCredential does not work when proxy is running #356

Open svrooij opened 1 year ago

svrooij commented 1 year ago

Description

It seems that the AzureCliCredential in the Azure.Identity nuget package. No longer works when the proxy is running.

here is the code to validate.

Expected behaviour

I expected the proxy to only change http requests that are in the list and not http requests to other services, but is seems to somehow intercept all https requests.

Actual behaviour

It refuses to give me a token

Steps to reproduce

  1. Check out this code
  2. Run az login if not logged in with the Azure CLI already
  3. Change the tenantId in the code the the actual tenant ID
  4. Start the proxy
  5. Validate that you're getting an error when starting the program
  6. Stop the proxy
  7. Validate that it now works
  8. Try out to figure a solution 🎉

Microsoft 365 Developer Proxy Version

0.11.1

Operating system (environment)

Windows

Shell

PowerShell

Additional Info

My best guess is that the Azure CLI is doing some sort of certificate pinning on the login.microsoftonline.com endpoint but this is pure me guessing what the issue might be.

garrytrinder commented 1 year ago

Sorry to hear that you've had an issue @svrooij however thank you for reporting, lets see what the issue might be.

Does the proxy show any output related to the request made to login.microsoftonline.com?

If you want to ensure that a URL is ignored you can prepend a URL with an exclamation mark in the urlsToWatch array in the m365proxyrc file to tell proxy to ignore requests made to it. See https://github.com/microsoft/m365-developer-proxy/wiki/Exclude-a-URL

svrooij commented 1 year ago

It displays nothing.... And login.microsoftonline.com is not in the list so there is nothing to exclude.

svrooij commented 1 year ago

I had a hard time reproducing the issue at first. It seems that the Azure CLI does some caching, so once it has successfully got a token, it will provide that token for roughly 50 minutes. Hence the reason why you should first check that it does not work by running the proxy while running the code and then retry without the proxy running.

The second time it works with and without the proxy running

garrytrinder commented 1 year ago

Thanks for the extra info.

I wonder if you need to also configure the Azure CLI to use the proxy, similar to how we need state the proxy when you send a request via PowerShell.

Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/me" -Proxy "http://localhost:8000"

You can configure the Azure CLI to use a proxy by settings the below environment variables

$env:HTTP_PROXY="http://localhost:8000"
$env:HTTPS_PROXY="http://localhost:8000"
svrooij commented 1 year ago

I have no way to control how it accesses the login endpoint, nor do I want to.

Eventually it's using AzureCliCredentials

This no longer functions when the proxy is running. Maybe because it also sets the proxy for the requests and then fails the certificate check. It should just leave all those requests alone.

garrytrinder commented 1 year ago

Thanks for the update @svrooij 👍

Looks like I've just had a similar issue with Teams Toolkit (see https://github.com/OfficeDev/TeamsFx/issues/10109) which might be related. When proxy is running (m365proxy -f 0), I can't start a debug session due to a failing task and there is nothing logged in the console output. Without proxy running it works fine.

I'll continue to investigate.

svrooij commented 1 year ago

@garrytrinder I suspect that it has something to do with certificate pinning.

According to SSLLabs https://www.ssllabs.com/ssltest/analyze.html?d=login.microsoftonline.com&s=20.190.151.70&hideResults=on&ignoreMismatch=on they have setup which certificate authorities are allowed to serve those domains through DNS CAA.

Any decent client (which I expect the actual httpclient those authentication code things are using) WILL terminate the request if they spot a different CA then those defined. Security wise, this is a smart move, as it's an additional step that helps prevent men in the middle attacks.

And because the proxy tries to intercept all https requests, anything talking to login.microsoftonline.com will fail no matter what.

Would it be possible to not touch some requests by hostname? In that case it should be configurable and the login urls should be excluded by default.

gavinbarron commented 1 year ago

Dev Proxy is built on top of Titanium Web Proxy. That component should, at least as I understand it, be passing through the cert information for any domain that is not explicitly included in the set of hosts for which we're examining traffic.

Here in the titanium code our OnBeforeTunnelConnectRequest implementation is being invoked.

I'll take a deeper look at this case when I wrap up another set of work to see if I can find out any more.

waldekmastykarz commented 10 months ago

I just had a look at it, and what I've seen:

I'll dig some more into it. It's certainly intriguing

svrooij commented 10 months ago

It's certainly intriguing @waldekmastykarz

🤣

Not only that it's in code that we both cannot control.

waldekmastykarz commented 10 months ago

If anything else, I'm interested if it's physics and we're stuck or if there's anything we can do about it