Skip to content

Commit c0f5a6b

Browse files
feature(#20): rewrite the tests to explicitly create and authenticate clients via the /api/v1/clients endpoint, removing the dependency on realms such as client_id and client_secret.
1 parent b71a1a4 commit c0f5a6b

1 file changed

Lines changed: 88 additions & 32 deletions

File tree

Applications/Backend/Tests/Integration/Endpoints/ConnectEndpointTests.cs

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ public sealed class ConnectEndpointTests(IntegrationEnvironmentFixture factory)
55
{
66
private readonly Fixture _fixture = new();
77

8-
[Fact(DisplayName = "[e2e] - when POST /openid/connect/token with valid realm credentials should return access token")]
9-
public async Task WhenPostTokenWithValidRealmCredentials_ShouldReturnAccessToken()
8+
[Fact(DisplayName = "[e2e] - when POST /openid/connect/token with valid client credentials should return access token")]
9+
public async Task WhenPostTokenWithValidClientCredentials_ShouldReturnAccessToken()
1010
{
1111
/* arrange: authenticate user and get access token */
12+
var clientCollection = factory.Services.GetRequiredService<IClientCollection>();
1213
var httpClient = factory.HttpClient.WithRealmHeader("master");
14+
1315
var userCredentials = new AuthenticationCredentials
1416
{
1517
Username = "federation.testing.user",
@@ -24,35 +26,46 @@ public async Task WhenPostTokenWithValidRealmCredentials_ShouldReturnAccessToken
2426

2527
httpClient.WithAuthorization(authentication.AccessToken);
2628

27-
/* arrange: create a realm to use as client */
28-
var payload = _fixture.Build<RealmCreationScheme>()
29-
.With(realm => realm.Name, $"test-realm-{Guid.NewGuid()}")
30-
.With(realm => realm.Description, $"test-description-{Guid.NewGuid()}")
29+
/* arrange: create a client */
30+
var payload = _fixture.Build<ClientCreationScheme>()
31+
.With(client => client.Name, "root")
32+
.With(client => client.Flows, [Grant.ClientCredentials])
33+
.With(client => client.RedirectUris, [])
3134
.Create();
3235

33-
var realmResponse = await httpClient.PostAsJsonAsync("api/v1/realms", payload);
34-
var realm = await realmResponse.Content.ReadFromJsonAsync<RealmDetailsScheme>();
36+
var response = await httpClient.PostAsJsonAsync("api/v1/clients", payload);
3537

36-
Assert.NotNull(realm);
37-
Assert.Equal(HttpStatusCode.Created, realmResponse.StatusCode);
38+
Assert.NotNull(response);
39+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
40+
41+
var filters = ClientFilters.WithSpecifications()
42+
.WithName(payload.Name)
43+
.Build();
44+
45+
var clients = await clientCollection.GetClientsAsync(filters);
46+
var client = clients.FirstOrDefault();
3847

39-
/* arrange: prepare client credentials using realm data */
48+
Assert.NotEmpty(clients);
49+
Assert.NotNull(client);
50+
51+
/* arrange: prepare client credentials */
4052
var credentials = new Dictionary<string, string>
4153
{
4254
{ "grant_type", "client_credentials" },
43-
{ "client_id", realm.ClientId },
44-
{ "client_secret", realm.ClientSecret }
55+
{ "client_id", client.ClientId },
56+
{ "client_secret", client.Secret }
4557
};
4658

4759
var content = new FormUrlEncodedContent(credentials);
4860
var connectClient = factory.HttpClient;
4961

5062
/* act: send POST request to token endpoint */
51-
var response = await connectClient.PostAsync("api/v1/protocol/open-id/connect/token", content);
52-
var grantedToken = await response.Content.ReadFromJsonAsync<ClientAuthenticationResult>();
63+
var httpResponse = await connectClient.PostAsync("api/v1/protocol/open-id/connect/token", content);
64+
var grantedToken = await httpResponse.Content.ReadFromJsonAsync<ClientAuthenticationResult>();
5365

5466
/* assert: response should be 200 OK */
55-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
67+
Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
68+
5669
Assert.NotNull(grantedToken);
5770
Assert.False(string.IsNullOrWhiteSpace(grantedToken.AccessToken));
5871
}
@@ -86,7 +99,9 @@ public async Task WhenPostTokenWithNonExistentClient_ShouldReturnUnauthorized()
8699
public async Task WhenPostTokenWithInvalidClientSecret_ShouldReturnUnauthorized()
87100
{
88101
/* arrange: authenticate user and get access token */
102+
var clientCollection = factory.Services.GetRequiredService<IClientCollection>();
89103
var httpClient = factory.HttpClient.WithRealmHeader("master");
104+
90105
var userCredentials = new AuthenticationCredentials
91106
{
92107
Username = "federation.testing.user",
@@ -100,37 +115,47 @@ public async Task WhenPostTokenWithInvalidClientSecret_ShouldReturnUnauthorized(
100115

101116
httpClient.WithAuthorization(authentication.AccessToken);
102117

103-
/* arrange: create a realm */
104-
var payload = _fixture.Build<RealmCreationScheme>()
105-
.With(realm => realm.Name, $"test-realm-{Guid.NewGuid()}")
106-
.With(realm => realm.Description, $"test-description-{Guid.NewGuid()}")
118+
/* arrange: create a client */
119+
var payload = _fixture.Build<ClientCreationScheme>()
120+
.With(client => client.Name, "admin")
121+
.With(client => client.Flows, [Grant.ClientCredentials])
122+
.With(client => client.RedirectUris, [])
107123
.Create();
108124

109-
var httpResponse = await httpClient.PostAsJsonAsync("api/v1/realms", payload);
110-
var realm = await httpResponse.Content.ReadFromJsonAsync<RealmDetailsScheme>();
125+
var response = await httpClient.PostAsJsonAsync("api/v1/clients", payload);
111126

112-
Assert.NotNull(realm);
127+
Assert.NotNull(response);
128+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
129+
130+
var filters = ClientFilters.WithSpecifications()
131+
.WithName(payload.Name)
132+
.Build();
133+
134+
var clients = await clientCollection.GetClientsAsync(filters);
135+
var client = clients.FirstOrDefault();
136+
137+
Assert.NotEmpty(clients);
138+
Assert.NotNull(client);
113139

114140
/* arrange: prepare credentials with wrong secret */
115141
var credentials = new Dictionary<string, string>
116142
{
117143
{ "grant_type", "client_credentials" },
118-
{ "client_id", realm.ClientId },
144+
{ "client_id", client.ClientId },
119145
{ "client_secret", "wrong-secret" }
120146
};
121147

122148
/* act: send POST request with invalid secret */
123-
124149
var content = new FormUrlEncodedContent(credentials);
125150
var connectClient = factory.HttpClient;
126151

127-
var response = await connectClient.PostAsync("api/v1/protocol/open-id/connect/token", content);
128-
var error = await response.Content.ReadFromJsonAsync<Error>();
152+
var httpResponse = await connectClient.PostAsync("api/v1/protocol/open-id/connect/token", content);
153+
var error = await httpResponse.Content.ReadFromJsonAsync<Error>();
129154

130155
/* assert: response should be 401 Unauthorized */
131156
Assert.NotNull(error);
132157

133-
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
158+
Assert.Equal(HttpStatusCode.Unauthorized, httpResponse.StatusCode);
134159
Assert.Equal(AuthenticationErrors.InvalidClientCredentials, error);
135160
}
136161

@@ -200,14 +225,16 @@ public async Task WhenPostTokenWithValidAuthorizationCode_ShouldReturnAccessToke
200225
// arrange: resolve required dependencies
201226
var tokenCollection = factory.Services.GetRequiredService<ITokenCollection>();
202227
var userCollection = factory.Services.GetRequiredService<IUserCollection>();
228+
var clientCollection = factory.Services.GetRequiredService<IClientCollection>();
203229

204-
// arrange: authenticate as master to create realm
230+
// arrange: authenticate as master to create client and realm
205231
var masterClient = factory.HttpClient.WithRealmHeader("master");
206232
var masterCredentials = new AuthenticationCredentials
207233
{
208234
Username = "federation.testing.user",
209235
Password = "federation.testing.password"
210236
};
237+
211238
var authentication = await masterClient.PostAsJsonAsync("api/v1/identity/authenticate", masterCredentials);
212239
var grantedToken = await authentication.Content.ReadFromJsonAsync<AuthenticationResult>();
213240

@@ -217,17 +244,46 @@ public async Task WhenPostTokenWithValidAuthorizationCode_ShouldReturnAccessToke
217244
masterClient.WithAuthorization(grantedToken.AccessToken);
218245

219246
// arrange: create realm
220-
var payload = _fixture.Build<RealmCreationScheme>()
247+
var realmPayload = _fixture.Build<RealmCreationScheme>()
221248
.With(realm => realm.Name, $"test-realm-{Guid.NewGuid()}")
222249
.With(realm => realm.Description, $"test-description-{Guid.NewGuid()}")
223250
.Create();
224251

225-
var realmResponse = await masterClient.PostAsJsonAsync("api/v1/realms", payload);
252+
var realmResponse = await masterClient.PostAsJsonAsync("api/v1/realms", realmPayload);
226253
var realm = await realmResponse.Content.ReadFromJsonAsync<RealmDetailsScheme>();
227254

228255
Assert.NotNull(realm);
229256
Assert.Equal(HttpStatusCode.Created, realmResponse.StatusCode);
230257

258+
// arrange: create client for authorization_code grant
259+
var realmMasterClient = factory.HttpClient.WithRealmHeader(realm.Name);
260+
var realmAuth = await realmMasterClient.PostAsJsonAsync("api/v1/identity/authenticate", masterCredentials);
261+
262+
var realmAdminClient = factory.HttpClient
263+
.WithRealmHeader(realm.Name)
264+
.WithAuthorization(grantedToken.AccessToken);
265+
266+
var payload = _fixture.Build<ClientCreationScheme>()
267+
.With(client => client.Name, "root")
268+
.With(client => client.Flows, [Grant.ClientCredentials])
269+
.With(client => client.RedirectUris, [])
270+
.Create();
271+
272+
var httpResponse = await realmAdminClient.PostAsJsonAsync("api/v1/clients", payload);
273+
274+
Assert.NotNull(httpResponse);
275+
Assert.Equal(HttpStatusCode.Created, httpResponse.StatusCode);
276+
277+
var clientFilters = ClientFilters.WithSpecifications()
278+
.WithName(payload.Name)
279+
.Build();
280+
281+
var clients = await clientCollection.GetClientsAsync(clientFilters);
282+
var client = clients.FirstOrDefault();
283+
284+
Assert.NotEmpty(clients);
285+
Assert.NotNull(client);
286+
231287
// arrange: create user for realm
232288
var credentials = new IdentityEnrollmentCredentials
233289
{
@@ -297,7 +353,7 @@ public async Task WhenPostTokenWithValidAuthorizationCode_ShouldReturnAccessToke
297353
{
298354
{ "grant_type", "authorization_code" },
299355
{ "code", authorizationCode },
300-
{ "client_id", realm.ClientId },
356+
{ "client_id", client.ClientId },
301357
{ "code_verifier", codeVerifier }
302358
};
303359

0 commit comments

Comments
 (0)