@@ -10,8 +10,6 @@ namespace Atlassian.Bitbucket
10
10
{
11
11
public class BitbucketHostProvider : IHostProvider
12
12
{
13
- public const bool USE_BEARER_TOKEN = true ;
14
- public const bool USE_BASIC_TOKEN = ! USE_BEARER_TOKEN ;
15
13
private readonly ICommandContext _context ;
16
14
private readonly IBitbucketAuthentication _bitbucketAuth ;
17
15
private readonly IBitbucketRestApi _bitbucketApi ;
@@ -96,7 +94,7 @@ private static void ValidateTargetUri(InputArguments input)
96
94
97
95
private async Task < ICredential > GetStoredCredentials ( InputArguments input )
98
96
{
99
- if ( _context . Settings . TryGetSetting ( BitbucketConstants . EnvironmentVariables . AlwaysRefreshCredentials ,
97
+ if ( _context . Settings . TryGetSetting ( BitbucketConstants . EnvironmentVariables . AlwaysRefreshCredentials ,
100
98
Constants . GitConfiguration . Credential . SectionName , BitbucketConstants . GitConfiguration . Credential . AlwaysRefreshCredentials ,
101
99
out string alwaysRefreshCredentials ) && alwaysRefreshCredentials . ToBooleanyOrDefault ( false ) )
102
100
{
@@ -110,16 +108,16 @@ private async Task<ICredential> GetStoredCredentials(InputArguments input)
110
108
111
109
var credentials = _context . CredentialStore . Get ( credentialService , input . UserName ) ;
112
110
113
- if ( credentials == null )
111
+ if ( credentials == null )
114
112
{
115
113
_context . Trace . WriteLine ( $ " Found none") ;
116
114
return null ;
117
115
}
118
116
119
- _context . Trace . WriteLine ( $ " Found credentials: { credentials . Account } /**********" ) ;
117
+ _context . Trace . WriteLineSecrets ( $ " Found credentials: { credentials . Account } /{{0}}" , new object [ ] { credentials . Password } ) ;
120
118
121
119
//check credentials are still valid
122
- if ( ! await ValidateCredentialsWork ( input , credentials , GetSupportedAuthenticationModes ( targetUri ) ) ) {
120
+ if ( ! await ValidateCredentialsWork ( input , credentials , GetSupportedAuthenticationModes ( targetUri ) ) ) {
123
121
return null ;
124
122
}
125
123
@@ -154,7 +152,7 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input)
154
152
155
153
var basicCredentials = await GetBasicCredentialsInteractive ( input , authModes ) ;
156
154
157
- if ( await ValidateCredentialsWork ( input , basicCredentials , authModes ) )
155
+ if ( await ValidateCredentialsWork ( input , basicCredentials , authModes ) )
158
156
{
159
157
return basicCredentials ;
160
158
}
@@ -181,8 +179,6 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input)
181
179
else
182
180
{
183
181
_context . Trace . WriteLine ( $ " Found refresh token: { refreshToken } ") ;
184
- // TODO: should we try and compute if the AT has expired and use it?
185
- // This needs support from the credential store to record the expiry time!
186
182
187
183
// It's very likely that any access token expired between the last time we used/stored it.
188
184
// To ensure the AT is as 'fresh' as it can be, always first try to use the refresh token
@@ -292,7 +288,7 @@ private static bool SupportsBasicAuth(AuthenticationModes authModes)
292
288
293
289
public AuthenticationModes GetSupportedAuthenticationModes ( Uri targetUri )
294
290
{
295
- if ( ! IsBitbucketOrg ( targetUri ) )
291
+ if ( ! IsBitbucketOrg ( targetUri ) )
296
292
{
297
293
// Bitbucket Server/DC should use Basic only
298
294
return BitbucketConstants . ServerAuthenticationModes ;
@@ -361,7 +357,7 @@ public Task EraseCredentialAsync(InputArguments input)
361
357
362
358
private async Task < string > ResolveOAuthUserNameAsync ( string accessToken )
363
359
{
364
- RestApiResult < UserInfo > result = await _bitbucketApi . GetUserInformationAsync ( null , accessToken , USE_BEARER_TOKEN ) ;
360
+ RestApiResult < UserInfo > result = await _bitbucketApi . GetUserInformationAsync ( null , accessToken , isBearerToken : true ) ;
365
361
if ( result . Succeeded )
366
362
{
367
363
return result . Response . UserName ;
@@ -372,7 +368,7 @@ private async Task<string> ResolveOAuthUserNameAsync(string accessToken)
372
368
373
369
private async Task < string > ResolveBasicAuthUserNameAsync ( string username , string password )
374
370
{
375
- RestApiResult < UserInfo > result = await _bitbucketApi . GetUserInformationAsync ( username , password , USE_BASIC_TOKEN ) ;
371
+ RestApiResult < UserInfo > result = await _bitbucketApi . GetUserInformationAsync ( username , password , isBearerToken : false ) ;
376
372
if ( result . Succeeded )
377
373
{
378
374
return result . Response . UserName ;
@@ -383,15 +379,15 @@ private async Task<string> ResolveBasicAuthUserNameAsync(string username, string
383
379
384
380
private async Task < bool > RequiresTwoFactorAuthenticationAsync ( ICredential credentials , AuthenticationModes authModes )
385
381
{
386
- _context . Trace . WriteLine ( $ "Check if 2FA si required for credentials ({ credentials . Account } /********** ) { authModes } ...") ;
382
+ _context . Trace . WriteLineSecrets ( $ "Check if 2FA si required for credentials ({ credentials . Account } /{{0}} ) { authModes } ...", new object [ ] { credentials . Password } ) ;
387
383
388
- if ( ! SupportsOAuth ( authModes ) )
384
+ if ( ! SupportsOAuth ( authModes ) )
389
385
{
390
386
return false ;
391
387
}
392
388
393
389
RestApiResult < UserInfo > result = await _bitbucketApi . GetUserInformationAsync (
394
- credentials . Account , credentials . Password , USE_BASIC_TOKEN ) ;
390
+ credentials . Account , credentials . Password , isBearerToken : false ) ;
395
391
switch ( result . StatusCode )
396
392
{
397
393
// 2FA may not be required
@@ -413,26 +409,30 @@ private async Task<bool> RequiresTwoFactorAuthenticationAsync(ICredential creden
413
409
414
410
private async Task < bool > ValidateCredentialsWork ( InputArguments input , ICredential credentials , AuthenticationModes authModes )
415
411
{
416
- if ( credentials == null )
412
+ if ( credentials == null )
417
413
{
418
414
return false ;
419
415
}
420
416
417
+ // TODO ideally we'd also check if the credentials have expired based on some local metadata (once/if we get such metadata storage),
418
+ // and return false if they have.
419
+ // This would be more efficient than having to make REST API calls to check.
420
+
421
421
var targetUri = input . GetRemoteUri ( ) ;
422
- _context . Trace . WriteLine ( $ "Validate credentials ({ credentials . Account } /********** ) are fresh for { targetUri } ...") ;
422
+ _context . Trace . WriteLineSecrets ( $ "Validate credentials ({ credentials . Account } /{{0}} ) are fresh for { targetUri } ...", new object [ ] { credentials . Password } ) ;
423
423
424
- if ( ! IsBitbucketOrg ( targetUri ) )
424
+ if ( ! IsBitbucketOrg ( targetUri ) )
425
425
{
426
426
// TODO Validate DC/Server credentials before returning them to Git
427
427
// Currently credentials for DC/Server are not checked by GCM.
428
- // Instead the validation relies on Git to try and fail with the creneitals and then request GCM to erase them
428
+ // Instead the validation relies on Git to try and fail with the credentials and then request GCM to erase them
429
429
_context . Trace . WriteLine ( "For DC/Server skip validating existing credentials" ) ;
430
430
return await Task . FromResult ( true ) ;
431
431
}
432
432
433
433
// Bitbucket supports both OAuth + Basic Auth unless there is explicit GCM configuration
434
434
// So the credentials could be for either scheme therefore need to potentiall test both posibilities.
435
- if ( SupportsOAuth ( authModes ) )
435
+ if ( SupportsOAuth ( authModes ) )
436
436
{
437
437
try
438
438
{
@@ -446,7 +446,7 @@ private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredenti
446
446
}
447
447
}
448
448
449
- if ( SupportsBasicAuth ( authModes ) )
449
+ if ( SupportsBasicAuth ( authModes ) )
450
450
{
451
451
try
452
452
{
0 commit comments