Unable to contact Azure DevOps Server invalid PAT

Hi,

I have installed Sonarqube as per the documentation on single server. The service is running fine but the Azure DevOps integration fails with the common error Invalid Azure URL or Personal Access Token

I reviewed other posts with similar error but couldn’t able to relate to the issue. Any assistance would be really helpful.

  • Sonarqube Community Version 9.9
  • Installed Sonarqube on single server
  • Azure DevOps Server 2020 is installed which fails the integration with the PAT error.
  • Verified the PAT and URL are correct

Following are the web.log in debug mode.

2023.02.14 10:52:29 DEBUG web[AYZN8OPEWmDA+/LFAAEb][o.s.a.c.a.AzureDevOpsHttpClient] check pat : [http://<azure-devops-servername>/tfs/OKCollection/_apis/projects?api-version=3.0]
2023.02.14 10:52:29 ERROR web[AYZN8OPEWmDA+/LFAAEb][o.s.a.c.a.AzureDevOpsHttpClient] Unable to contact Azure DevOps server for request [http://<azure-devops-servername>/tfs/OKCollection/_apis/projects?api-version=3.0]: Invalid personal access token
2023.02.14 10:52:29 DEBUG web[AYZN8OPEWmDA+/LFAAEb][o.i.c.TaskRunner] Q10002 scheduled after   0 µs: OkHttp ConnectionPool
2023.02.14 10:52:29 DEBUG web[][o.i.c.TaskRunner] Q10002 starting              : OkHttp ConnectionPool
2023.02.14 10:52:29 DEBUG web[][o.i.c.TaskRunner] Q10002 run again after 300 s : OkHttp ConnectionPool
2023.02.14 10:52:29 DEBUG web[][o.i.c.TaskRunner] Q10002 finished run in 208 µs: OkHttp ConnectionPool
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.MainClientExec] [exchange: 2751] start execution
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAddCookies] CookieSpec selected: default
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAuthCache] Re-using cached 'basic' auth scheme for http://127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAuthCache] No credentials for preemptive authentication
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2751] Request connection for {}->http://127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection request: [route: {}->http://127.0.0.1:9001][total kept alive: 2; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection leased: [id: http-outgoing-1][route: {}->http://127.0.0.1:9001][total kept alive: 1; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2751] Connection allocated: CPoolProxy{http-outgoing-1 [ACTIVE]}
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Attempt 1 to execute request
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Target auth state: UNCHALLENGED
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Proxy auth state: UNCHALLENGED
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> GET /_cluster/health?master_timeout=30s&level=cluster&timeout=30s HTTP/1.1
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> X-Elastic-Client-Meta: es=7.17.8,jv=17,t=7.17.8,hc=4.1.4,kt=1.6
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Content-Length: 0
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Host: 127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Connection: Keep-Alive
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> User-Agent: elasticsearch-java/7.17.8 (Java/17.0.6)
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Request completed
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << HTTP/1.1 200 OK
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << X-elastic-product: Elasticsearch
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << content-type: application/json; charset=UTF-8
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << content-length: 387
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Response received HTTP/1.1 200 OK
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Consume content
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2751] Connection can be kept alive indefinitely
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2751] Response processed
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2751] releasing connection
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Releasing connection: [id: http-outgoing-1][route: {}->http://127.0.0.1:9001][total kept alive: 1; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection [id: http-outgoing-1][route: {}->http://127.0.0.1:9001] can be kept alive indefinitely
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection released: [id: http-outgoing-1][route: {}->http://127.0.0.1:9001][total kept alive: 2; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.MainClientExec] [exchange: 2752] start execution
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAddCookies] CookieSpec selected: default
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAuthCache] Re-using cached 'basic' auth scheme for http://127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.c.p.RequestAuthCache] No credentials for preemptive authentication
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2752] Request connection for {}->http://127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection request: [route: {}->http://127.0.0.1:9001][total kept alive: 2; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.PoolingNHttpClientConnectionManager] Connection leased: [id: http-outgoing-1][route: {}->http://127.0.0.1:9001][total kept alive: 1; route allocated: 2 of 10; total allocated: 2 of 30]
2023.02.14 10:52:34 DEBUG web[AYZN8OPEWmDA+/LFAAEd][o.a.h.i.n.c.InternalHttpAsyncClient] [exchange: 2752] Connection allocated: CPoolProxy{http-outgoing-1 [ACTIVE]}
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Attempt 1 to execute request
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Target auth state: UNCHALLENGED
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Proxy auth state: UNCHALLENGED
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> GET /_stats?level=shards HTTP/1.1
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> X-Elastic-Client-Meta: es=7.17.8,jv=17,t=7.17.8,hc=4.1.4,kt=1.6
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Content-Length: 0
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Host: 127.0.0.1:9001
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> Connection: Keep-Alive
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 >> User-Agent: elasticsearch-java/7.17.8 (Java/17.0.6)
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Request completed
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << HTTP/1.1 200 OK
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << X-elastic-product: Elasticsearch
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << content-type: application/json; charset=UTF-8
2023.02.14 10:52:34 DEBUG web[][o.a.http.headers] http-outgoing-1 << content-length: 106915
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Response received HTTP/1.1 200 OK
2023.02.14 10:52:34 DEBUG web[][o.a.h.i.n.c.MainClientExec] [exchange: 2752] Consume content

Hi,

At what point do you see this error? Is it when you test the configuration, or later when you actually try to use it? Is there something “helpful” on your network between SonarQube and Azure that could be interfering?

 
Ann

Thank you for your reply.

I get the error while configuration at the initial stage. Attached screenshot.

I also did wireshark on the sonarcube instance to check the network communication. It shows similar error for invalid credentials.

I verified the PAT and the URL by running remote git and confirmed that its correct.

$ git ls-remote http://:<PAT Token>@<Azure DevOps URL>
ccee6bf099234ba19eb0928a1b04f814ae811e41        HEAD
ccee6bf099234ba19eb0928a1b04f814ae811e41        refs/heads/main
ccee6bf099234ba19eb0928a1b04f814ae811e41        refs/heads/master

Hi,

I don’t know what to tell you. It’s Azure is saying the token isn’t valid, which you’ve verified via Wireshark.

It may be worth checking that there’s no strange invisible character in the value SonarQube has for the PAT. Does your PAT include any non-UTF-8 characters?

 
Ann

One more thing to add here which I noticed with the wireshark, the authorization token sending from SonarQube to Azure DevOps is via Basic

As per the documentation below Azure DevOps doesn’t support IIS Basic auth for PAT.

Enabling IIS Basic Authentication invalidates using Personal Access Tokens

Does it make a difference? How do I change it in Sonarqube to avoid using BASIC auth?

Hi,

Hmm… I’m not sure at this point. I’ve called for other eyes.

 
Ann

1 Like

Hi there, @zimmy-ae,

Many thanks for your query and detailed explanations. :slight_smile:

First of all, would it be possible to query the URL directly using curl, using your PAT as authorization header in the following way:

curl -x GET /tfs/OKCollection/_apis/projects?api-version=3.0 -H Authorization: Bearer <token>

and then

curl -x GET /tfs/OKCollection/_apis/projects?api-version=3.0 -H Authorization: Basic base64(:${PAT})

…?

From this we can then diagnose further.

Regards

1 Like

Thank you @ganncamp for your support.

Hi @alain.kermis ,

Thank you for looking into it. I checked the curl , below is the output.

root@:~# curl -x GET http://<Azure DevOps URL>/tfs/OKCollection/_apis/projects?api-version=3.0 -H "Authorization: Basic {$PAT}"
curl: (5) Could not resolve proxy: GET

root@:~# curl -x GET http://<Azure DevOps URL>/tfs/OKCollection/_apis/projects?api-version=3.0 -H "Authorization: Basic base64(:${PAT})"
curl: (5) Could not resolve proxy: GET

Hi again,

I am so sorry; I made a typo. Could you re-rerun the requests, but with -X, as the ‘X’ should be capital?

Regards

1 Like

Hi @alain.kermis

root@:~# curl -X GET http://<Azure DevOps URL>/tfs/OKCollection/_apis/projects?api-version=3.0 -H "Authorization: Basic {$PAT}"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
fieldset{padding:0 15px 10px 15px;}
h1{font-size:2.4em;margin:0;color:#FFF;}
h2{font-size:1.7em;margin:0;color:#CC0000;}
h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;}
#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
background-color:#555555;}
#content{margin:0 0 0 2%;position:relative;}
.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
-->
</style>
</head>
<body>
<div id="header"><h1>Server Error</h1></div>
<div id="content">
 <div class="content-container"><fieldset>
  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>
  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>
 </fieldset></div>
</div>
</body>
</html>

Just to add here , I tried to directly access the Azure DevOps API via Postman, it works! But with NTLM Authentication. Bearer token authentication doesn’t work.

Hi @ganncamp @alain.kermis

Awaiting for someone to engage and assist into this.

Hi there again, @zimmy-ae,

It is not clear whether or not you are using IIS Basic Authentication on your Azure DevOps instance. If so, is it possible for you to disable it and try again, because as you mentioned, the platform does not support it in conjunction with PATs.

Regards

Thanks @alain.kermis for your reply.

I am not using IIS Basic Authentication on Azure DevOps instance. Its already disabled, still when I see the trace from sonarqube to AzureDevOps, its using sending via Basic Auth.

Azure DevOps IIS

image

Is there anything else I can provide you which can give you better clarity on where is the issue? I am currently stuck at a situation where without this integration we will not be able to board into sonarqube completely.

Looking forward for some insight into it.

Hi again,

We gave it a try on our configuration as so:

image

We did notice that Basic Authentication feature is not installed on our side, so could it be that is why it works on our side. Would you like to try it by removing this feature?

This is the curl command we used:

curl -X GET "https://<URL GOES HERE>/_apis/projects?api-version=3.0" -u ":${PAT}"

Please let us know!

Hi @alain.kermis

Thank you for taking time to reply.

I removed Basic Authentication feature on ADO Server. Even after removing issue remains same.

The curl command gave the below output.

root@:~# curl -X GET "http://${URL}/_apis/projects?api-version=3.0" -u ":${PAT}"

{"count":29,"value":[{"id":"347f6546-c87d-4f79-8b43-715699566d1a","name":"SampleCore","url":"http://<url>/tfs/OKCollection/_apis/projects/347f6546-c87d-4f79-8b43-715699566d1a","state":"wellFormed","revision":78,"visibility":"private","lastUpdateTime":"2018-09-06T05:33:16.32Z"},{"id":"72230801-993e-4152-995d-66bdbee268b6","name":"CPDComponents","url":"http://stgvcs01.fabric.local:8080/tfs/OKCollection/_apis/projects/72230801-993e-4152-995d-66bdbee268b6","state":"wellFormed","revision":54,"visibility":"private","lastUpdateTime":"2018-07-04T05:59:30.747Z"},{"id":"d2b59783-047e-411f-bc96-4530332669e0","name":"AM-DApps","description":"Docker Application Deployment testing","url":"http://<url>/tfs/OKCollection/_apis/projects/d2b59783-047e-411f-bc96-4530332669e0","state":"wellFormed","revision":190,"visibility":"private","lastUpdateTime":"2019-07-17T11:40:17.42Z"},{"id":"59c49600-5c5b-46f3-b3f7-93e9e4daab5e","name":"Rel_Auto_Test02","url":"http://<url>/tfs/OKCollection/_apis/projects/59c49600-5c5b-46f3-b3f7-93e9e4daab5e","state":"wellFormed","revision":233,"visibility":"private","lastUpdateTime":"2020-01-21T09:11:21.08Z"},{"id":"4ad8fa34-13cc-45cc-a3e8-c17e05f9e7ea","name":"NewProject-TestReleasePipeline-20200114","url":"http://<url>/tfs/OKCollection/_apis/projects/4ad8fa34-13cc-45cc-a3e8-c17e05f9e7ea","state":"wellFormed","revision":225,"visibility":"private","lastUpdateTime":"2020-01-14T09:52:36.3Z"},

Hi again,

This is the exact request that SonarQube sends to retrieve the projects list. From what I can see from your response, the PAT is In fact working.

Could you compare that your SQ is making this exact curl request? If this curl worked for you in this regard to get the list of projects, it should have also worked the same from your SQ instance because it is the same request.

Regards

Thanks @alain.kermis for your reply.

After I uninstalled the Basic Authentication feature for Azure DevOps Server, the integration is successful.
Thank you for your assistance.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.