Skip to content

Commit ffbc525

Browse files
Corina Gumclaude
authored andcommitted
Add sovereign cloud validation and ActiveBotScope tests
- CloudEnvironmentTests: ClientCredentials cloud property defaults and assignment - BotTokenClientTests: ActiveBotScope defaults, overrides, and usage in GetAsync - TeamsValidationSettingsTests: sovereign cloud issuers, JWKS, login endpoints, tenant-specific URLs, and audience handling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 53b8a17 commit ffbc525

3 files changed

Lines changed: 182 additions & 0 deletions

File tree

Tests/Microsoft.Teams.Api.Tests/Auth/CloudEnvironmentTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,34 @@ public void WithOverrides_AllOverrides_ReplacesAllProperties()
176176
Assert.Equal("g", result.ChannelService);
177177
Assert.Equal("h", result.OAuthRedirectUrl);
178178
}
179+
180+
[Fact]
181+
public void ClientCredentials_DefaultsToPublicCloud()
182+
{
183+
var creds = new ClientCredentials("id", "secret");
184+
Assert.Same(CloudEnvironment.Public, creds.Cloud);
185+
}
186+
187+
[Fact]
188+
public void ClientCredentials_CloudCanBeSet()
189+
{
190+
var creds = new ClientCredentials("id", "secret")
191+
{
192+
Cloud = CloudEnvironment.USGov
193+
};
194+
Assert.Same(CloudEnvironment.USGov, creds.Cloud);
195+
}
196+
197+
[Fact]
198+
public void ClientCredentials_UsesCloudLoginTenantWhenTenantIdNull()
199+
{
200+
var creds = new ClientCredentials("id", "secret")
201+
{
202+
Cloud = CloudEnvironment.USGov
203+
};
204+
205+
// TenantId is null, so Cloud.LoginTenant should be used
206+
Assert.Null(creds.TenantId);
207+
Assert.Equal("MicrosoftServices.onmicrosoft.us", creds.Cloud.LoginTenant);
208+
}
179209
}

Tests/Microsoft.Teams.Api.Tests/Clients/BotTokenClientTests.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,49 @@ public async Task BotTokenClient_HttpClientOptions_Async()
147147
Assert.Equal(expectedTenantId, actualTenantId);
148148
Assert.Equal("https://api.botframework.com/.default", actualScope[0]);
149149
}
150+
151+
[Fact]
152+
public void ActiveBotScope_DefaultsToPublicBotScope()
153+
{
154+
var client = new BotTokenClient();
155+
Assert.Equal(BotTokenClient.BotScope, client.ActiveBotScope);
156+
Assert.Equal("https://api.botframework.com/.default", client.ActiveBotScope);
157+
}
158+
159+
[Fact]
160+
public void ActiveBotScope_CanBeOverridden()
161+
{
162+
var client = new BotTokenClient();
163+
client.ActiveBotScope = "https://api.botframework.us/.default";
164+
Assert.Equal("https://api.botframework.us/.default", client.ActiveBotScope);
165+
}
166+
167+
[Fact]
168+
public void BotScope_StaticFieldUnchanged()
169+
{
170+
Assert.Equal("https://api.botframework.com/.default", BotTokenClient.BotScope);
171+
}
172+
173+
[Fact]
174+
public async Task BotTokenClient_ActiveBotScope_UsedInGetAsync()
175+
{
176+
var cancellationToken = new CancellationToken();
177+
string[] actualScope = [""];
178+
TokenFactory tokenFactory = new TokenFactory(async (tenantId, scope) =>
179+
{
180+
actualScope = scope;
181+
return await Task.FromResult<ITokenResponse>(new TokenResponse
182+
{
183+
TokenType = "Bearer",
184+
AccessToken = accessToken
185+
});
186+
});
187+
var credentials = new TokenCredentials("clientId", tokenFactory);
188+
var botTokenClient = new BotTokenClient(cancellationToken);
189+
botTokenClient.ActiveBotScope = "https://api.botframework.us/.default";
190+
191+
await botTokenClient.GetAsync(credentials);
192+
193+
Assert.Equal("https://api.botframework.us/.default", actualScope[0]);
194+
}
150195
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Teams.Api.Auth;
5+
using Microsoft.Teams.Plugins.AspNetCore.Extensions;
6+
7+
namespace Microsoft.Teams.Plugins.AspNetCore.Tests.Extensions;
8+
9+
public class TeamsValidationSettingsTests
10+
{
11+
[Fact]
12+
public void DefaultConstructor_UsesPublicCloud()
13+
{
14+
var settings = new TeamsValidationSettings();
15+
16+
Assert.Equal("https://login.botframework.com/v1/.well-known/openidconfiguration", settings.OpenIdMetadataUrl);
17+
Assert.Equal("https://login.microsoftonline.com", settings.LoginEndpoint);
18+
Assert.Contains("https://api.botframework.com", settings.Issuers);
19+
}
20+
21+
[Fact]
22+
public void USGovCloud_HasCorrectSettings()
23+
{
24+
var settings = new TeamsValidationSettings(CloudEnvironment.USGov);
25+
26+
Assert.Equal("https://login.botframework.azure.us/v1/.well-known/openidconfiguration", settings.OpenIdMetadataUrl);
27+
Assert.Equal("https://login.microsoftonline.us", settings.LoginEndpoint);
28+
Assert.Contains("https://api.botframework.us", settings.Issuers);
29+
}
30+
31+
[Fact]
32+
public void ChinaCloud_HasCorrectSettings()
33+
{
34+
var settings = new TeamsValidationSettings(CloudEnvironment.China);
35+
36+
Assert.Equal("https://login.botframework.azure.cn/v1/.well-known/openidconfiguration", settings.OpenIdMetadataUrl);
37+
Assert.Equal("https://login.partner.microsoftonline.cn", settings.LoginEndpoint);
38+
Assert.Contains("https://api.botframework.azure.cn", settings.Issuers);
39+
}
40+
41+
[Fact]
42+
public void AllClouds_IncludeEmulatorIssuers()
43+
{
44+
var clouds = new[] { CloudEnvironment.Public, CloudEnvironment.USGov, CloudEnvironment.USGovDoD, CloudEnvironment.China };
45+
46+
foreach (var cloud in clouds)
47+
{
48+
var settings = new TeamsValidationSettings(cloud);
49+
50+
// Emulator issuers should always be present
51+
Assert.Contains(settings.Issuers, i => i.Contains("d6d49420-f39b-4df7-a1dc-d59a935871db"));
52+
Assert.Contains(settings.Issuers, i => i.Contains("f8cdef31-a31e-4b4a-93e4-5f571e91255a"));
53+
}
54+
}
55+
56+
[Fact]
57+
public void GetTenantSpecificOpenIdMetadataUrl_UsesCloudLoginEndpoint()
58+
{
59+
var settings = new TeamsValidationSettings(CloudEnvironment.USGov);
60+
61+
var url = settings.GetTenantSpecificOpenIdMetadataUrl("my-tenant");
62+
63+
Assert.Equal("https://login.microsoftonline.us/my-tenant/v2.0/.well-known/openid-configuration", url);
64+
}
65+
66+
[Fact]
67+
public void GetTenantSpecificOpenIdMetadataUrl_DefaultsToCommon()
68+
{
69+
var settings = new TeamsValidationSettings(CloudEnvironment.China);
70+
71+
var url = settings.GetTenantSpecificOpenIdMetadataUrl(null);
72+
73+
Assert.Equal("https://login.partner.microsoftonline.cn/common/v2.0/.well-known/openid-configuration", url);
74+
}
75+
76+
[Fact]
77+
public void GetValidIssuersForTenant_UsesCloudLoginEndpoint()
78+
{
79+
var settings = new TeamsValidationSettings(CloudEnvironment.USGov);
80+
81+
var issuers = settings.GetValidIssuersForTenant("my-tenant").ToList();
82+
83+
Assert.Single(issuers);
84+
Assert.Equal("https://login.microsoftonline.us/my-tenant/", issuers[0]);
85+
}
86+
87+
[Fact]
88+
public void GetValidIssuersForTenant_ReturnsEmptyForNullTenant()
89+
{
90+
var settings = new TeamsValidationSettings(CloudEnvironment.USGov);
91+
92+
var issuers = settings.GetValidIssuersForTenant(null).ToList();
93+
94+
Assert.Empty(issuers);
95+
}
96+
97+
[Fact]
98+
public void AddDefaultAudiences_AddsClientIdAndApiPrefix()
99+
{
100+
var settings = new TeamsValidationSettings(CloudEnvironment.USGov);
101+
102+
settings.AddDefaultAudiences("my-client-id");
103+
104+
Assert.Contains("my-client-id", settings.Audiences);
105+
Assert.Contains("api://my-client-id", settings.Audiences);
106+
}
107+
}

0 commit comments

Comments
 (0)