@@ -511,6 +511,102 @@ public async Task AzureReposProvider_GetCredentialAsync_PatMode_ExistingPat_Retu
511
511
Assert . Equal ( personalAccessToken , credential . Password ) ;
512
512
}
513
513
514
+ [ Fact ]
515
+ public async Task AzureReposProvider_GetCredentialAsync_ManagedIdentity_ReturnsManagedIdCredential ( )
516
+ {
517
+ var input = new InputArguments ( new Dictionary < string , string >
518
+ {
519
+ [ "protocol" ] = "https" ,
520
+ [ "host" ] = "dev.azure.com" ,
521
+ [ "path" ] = "org/proj/_git/repo"
522
+ } ) ;
523
+
524
+ const string accessToken = "MANAGED-IDENTITY-TOKEN" ;
525
+ const string managedIdentity = "MANAGED-IDENTITY" ;
526
+
527
+ var context = new TestCommandContext
528
+ {
529
+ Environment =
530
+ {
531
+ Variables =
532
+ {
533
+ [ AzureDevOpsConstants . EnvironmentVariables . ManagedIdentity ] = managedIdentity
534
+ }
535
+ }
536
+ } ;
537
+
538
+ var azDevOps = Mock . Of < IAzureDevOpsRestApi > ( ) ;
539
+ var authorityCache = Mock . Of < IAzureDevOpsAuthorityCache > ( ) ;
540
+ var userMgr = Mock . Of < IAzureReposBindingManager > ( ) ;
541
+ var msAuthMock = new Mock < IMicrosoftAuthentication > ( ) ;
542
+
543
+ msAuthMock . Setup ( x => x . GetTokenForManagedIdentityAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) ) )
544
+ . ReturnsAsync ( new MockMsAuthResult { AccessToken = accessToken } ) ;
545
+
546
+ var provider = new AzureReposHostProvider ( context , azDevOps , msAuthMock . Object , authorityCache , userMgr ) ;
547
+
548
+ ICredential credential = await provider . GetCredentialAsync ( input ) ;
549
+
550
+ Assert . NotNull ( credential ) ;
551
+ Assert . Equal ( managedIdentity , credential . Account ) ;
552
+ Assert . Equal ( accessToken , credential . Password ) ;
553
+
554
+ msAuthMock . Verify (
555
+ x => x . GetTokenForManagedIdentityAsync ( managedIdentity ,
556
+ AzureDevOpsConstants . AzureDevOpsResourceId ) , Times . Once ) ;
557
+ }
558
+
559
+ [ Fact ]
560
+ public async Task AzureReposProvider_GetCredentialAsync_ServicePrincipal_ReturnsSPCredential ( )
561
+ {
562
+ var input = new InputArguments ( new Dictionary < string , string >
563
+ {
564
+ [ "protocol" ] = "https" ,
565
+ [ "host" ] = "dev.azure.com" ,
566
+ [ "path" ] = "org/proj/_git/repo"
567
+ } ) ;
568
+
569
+ const string accessToken = "SP-TOKEN" ;
570
+ const string tenantId = "78B1822F-107D-40A3-A29C-AB68D8066074" ;
571
+ const string clientId = "49B4DC1A-58A8-4EEE-A81B-616A40D0BA64" ;
572
+ const string servicePrincipal = $ "{ tenantId } /{ clientId } ";
573
+ const string servicePrincipalSecret = "CLIENT-SECRET" ;
574
+
575
+ var context = new TestCommandContext
576
+ {
577
+ Environment =
578
+ {
579
+ Variables =
580
+ {
581
+ [ AzureDevOpsConstants . EnvironmentVariables . ServicePrincipalId ] = servicePrincipal ,
582
+ [ AzureDevOpsConstants . EnvironmentVariables . ServicePrincipalSecret ] = servicePrincipalSecret
583
+ }
584
+ }
585
+ } ;
586
+
587
+ var azDevOps = Mock . Of < IAzureDevOpsRestApi > ( ) ;
588
+ var authorityCache = Mock . Of < IAzureDevOpsAuthorityCache > ( ) ;
589
+ var userMgr = Mock . Of < IAzureReposBindingManager > ( ) ;
590
+ var msAuthMock = new Mock < IMicrosoftAuthentication > ( ) ;
591
+
592
+ msAuthMock . Setup ( x =>
593
+ x . GetTokenForServicePrincipalAsync ( It . IsAny < ServicePrincipalIdentity > ( ) , It . IsAny < string [ ] > ( ) ) )
594
+ . ReturnsAsync ( new MockMsAuthResult { AccessToken = accessToken } ) ;
595
+
596
+ var provider = new AzureReposHostProvider ( context , azDevOps , msAuthMock . Object , authorityCache , userMgr ) ;
597
+
598
+ ICredential credential = await provider . GetCredentialAsync ( input ) ;
599
+
600
+ Assert . NotNull ( credential ) ;
601
+ Assert . Equal ( clientId , credential . Account ) ;
602
+ Assert . Equal ( accessToken , credential . Password ) ;
603
+
604
+ msAuthMock . Verify ( x => x . GetTokenForServicePrincipalAsync (
605
+ It . Is < ServicePrincipalIdentity > ( sp => sp . TenantId == tenantId && sp . Id == clientId ) ,
606
+ It . Is < string [ ] > ( scopes => scopes . Length == 1 && scopes [ 0 ] == AzureDevOpsConstants . AzureDevOpsDefaultScopes [ 0 ] ) ) ,
607
+ Times . Once ) ;
608
+ }
609
+
514
610
[ Fact ]
515
611
public async Task AzureReposHostProvider_ConfigureAsync_UseHttpPathSetTrue_DoesNothing ( )
516
612
{
0 commit comments