1- namespace ServiceControl . AcceptanceTests . Security . OpenIdConnect
1+ namespace ServiceControl . AcceptanceTests . Security . OpenIdConnect ;
2+
3+ using System . Net . Http ;
4+ using System . Security . Claims ;
5+ using System . Text . Json ;
6+ using System . Threading . Tasks ;
7+ using AcceptanceTesting ;
8+ using AcceptanceTesting . OpenIdConnect ;
9+ using Infrastructure . Auth ;
10+ using Infrastructure . WebApi ;
11+ using NServiceBus . AcceptanceTesting ;
12+ using NUnit . Framework ;
13+
14+ /// <summary>
15+ /// my/permissions and my/permissions/all
16+ /// These endpoints let a client (e.g. ServicePulse) discover what the current user is allowed to
17+ /// do: the full granular permission list, and a simplified per-area summary used to gate UI
18+ /// sections. Both are governed by the caller's role claims via <see cref="RolePermissions"/>.
19+ /// </summary>
20+ class When_my_permissions_are_requested : AcceptanceTest
221{
3- using System . Net . Http ;
4- using System . Security . Claims ;
5- using System . Text . Json ;
6- using System . Threading . Tasks ;
7- using AcceptanceTesting ;
8- using AcceptanceTesting . OpenIdConnect ;
9- using Infrastructure . Auth ;
10- using Infrastructure . WebApi ;
11- using NServiceBus . AcceptanceTesting ;
12- using NUnit . Framework ;
13-
14- /// <summary>
15- /// my/permissions and my/permissions/all
16- /// These endpoints let a client (e.g. ServicePulse) discover what the current user is allowed to
17- /// do: the full granular permission list, and a simplified per-area summary used to gate UI
18- /// sections. Both are governed by the caller's role claims via <see cref="RolePermissions"/>.
19- /// </summary>
20- class When_my_permissions_are_requested : AcceptanceTest
22+ OpenIdConnectTestConfiguration configuration ;
23+ MockOidcServer mockOidcServer ;
24+
25+ const string TestAudience = "api://test-audience" ;
26+
27+ [ SetUp ]
28+ public void ConfigureAuth ( )
2129 {
22- OpenIdConnectTestConfiguration configuration ;
23- MockOidcServer mockOidcServer ;
30+ mockOidcServer = new MockOidcServer ( audience : TestAudience ) ;
31+ mockOidcServer . Start ( ) ;
32+
33+ configuration = new OpenIdConnectTestConfiguration ( ServiceControlInstanceType . Primary )
34+ . WithConfigurationValidationDisabled ( )
35+ . WithAuthenticationEnabled ( )
36+ . WithRoleBasedAuthorizationEnabled ( )
37+ . WithAuthority ( mockOidcServer . Authority )
38+ . WithAudience ( TestAudience )
39+ . WithRequireHttpsMetadata ( false ) ;
40+ }
2441
25- const string TestAudience = "api://test-audience" ;
42+ [ TearDown ]
43+ public void CleanupAuth ( )
44+ {
45+ configuration ? . Dispose ( ) ;
46+ mockOidcServer ? . Dispose ( ) ;
47+ }
2648
27- [ SetUp ]
28- public void ConfigureAuth ( )
29- {
30- mockOidcServer = new MockOidcServer ( audience : TestAudience ) ;
31- mockOidcServer . Start ( ) ;
32-
33- configuration = new OpenIdConnectTestConfiguration ( ServiceControlInstanceType . Primary )
34- . WithConfigurationValidationDisabled ( )
35- . WithAuthenticationEnabled ( )
36- . WithRoleBasedAuthorizationEnabled ( )
37- . WithAuthority ( mockOidcServer . Authority )
38- . WithAudience ( TestAudience )
39- . WithRequireHttpsMetadata ( false ) ;
40- }
49+ [ Test ]
50+ public async Task Should_reject_requests_without_bearer_token ( )
51+ {
52+ HttpResponseMessage response = null ;
4153
42- [ TearDown ]
43- public void CleanupAuth ( )
44- {
45- configuration ? . Dispose ( ) ;
46- mockOidcServer ? . Dispose ( ) ;
47- }
54+ _ = await Define < Context > ( )
55+ . Done ( async ctx =>
56+ {
57+ response = await OpenIdConnectAssertions . SendRequestWithoutAuth (
58+ HttpClient ,
59+ HttpMethod . Get ,
60+ "/api/my/permissions/all" ) ;
61+ return response != null ;
62+ } )
63+ . Run ( ) ;
64+
65+ OpenIdConnectAssertions . AssertUnauthorized ( response ) ;
66+ }
4867
49- [ Test ]
50- public async Task Should_reject_requests_without_bearer_token ( )
51- {
52- HttpResponseMessage response = null ;
53-
54- _ = await Define < Context > ( )
55- . Done ( async ctx =>
56- {
57- response = await OpenIdConnectAssertions . SendRequestWithoutAuth (
58- HttpClient ,
59- HttpMethod . Get ,
60- "/api/my/permissions/all" ) ;
61- return response != null ;
62- } )
63- . Run ( ) ;
64-
65- OpenIdConnectAssertions . AssertUnauthorized ( response ) ;
66- }
68+ [ Test ]
69+ public async Task Should_return_only_the_permissions_granted_to_the_reader_role ( )
70+ {
71+ var descriptor = await GetPermissions ( RolePermissions . Reader ) ;
6772
68- [ Test ]
69- public async Task Should_return_only_the_permissions_granted_to_the_reader_role ( )
70- {
71- var descriptor = await GetPermissions ( RolePermissions . Reader ) ;
73+ Assert . That ( descriptor . Permissions , Is . EquivalentTo ( RolePermissions . GetPermissions ( RolePermissions . Reader ) ) ) ;
74+ }
7275
73- Assert . That ( descriptor . Permissions , Is . EquivalentTo ( RolePermissions . GetPermissions ( RolePermissions . Reader ) ) ) ;
74- }
76+ [ Test ]
77+ public async Task Should_return_every_known_permission_for_the_writer_role ( )
78+ {
79+ var descriptor = await GetPermissions ( RolePermissions . Writer ) ;
7580
76- [ Test ]
77- public async Task Should_return_every_known_permission_for_the_writer_role ( )
78- {
79- var descriptor = await GetPermissions ( RolePermissions . Writer ) ;
81+ Assert . That ( descriptor . Permissions , Is . EquivalentTo ( Permissions . All ) ) ;
82+ }
8083
81- Assert . That ( descriptor . Permissions , Is . EquivalentTo ( Permissions . All ) ) ;
82- }
84+ [ Test ]
85+ public async Task Should_summarize_the_reader_role_as_read_only ( )
86+ {
87+ var summary = await GetSummary ( RolePermissions . Reader ) ;
8388
84- [ Test ]
85- public async Task Should_summarize_the_reader_role_as_read_only ( )
89+ using ( Assert . EnterMultipleScope ( ) )
8690 {
87- var summary = await GetSummary ( RolePermissions . Reader ) ;
88-
89- using ( Assert . EnterMultipleScope ( ) )
90- {
91- Assert . That ( summary . FailedMessagesRead , Is . True ) ;
92- Assert . That ( summary . FailedMessagesWrite , Is . False ) ;
93- Assert . That ( summary . AuditingRead , Is . True ) ;
94- Assert . That ( summary . MonitoringRead , Is . True ) ;
95- Assert . That ( summary . MonitoringWrite , Is . False ) ;
96- Assert . That ( summary . AdminRead , Is . True ) ;
97- Assert . That ( summary . AdminWrite , Is . False ) ;
98- }
91+ Assert . That ( summary . FailedMessagesRead , Is . True ) ;
92+ Assert . That ( summary . FailedMessagesWrite , Is . False ) ;
93+ Assert . That ( summary . AuditingRead , Is . True ) ;
94+ Assert . That ( summary . MonitoringRead , Is . True ) ;
95+ Assert . That ( summary . MonitoringWrite , Is . False ) ;
96+ Assert . That ( summary . AdminRead , Is . True ) ;
97+ Assert . That ( summary . AdminWrite , Is . False ) ;
9998 }
99+ }
100100
101- [ Test ]
102- public async Task Should_summarize_the_writer_role_as_full_access ( )
103- {
104- var summary = await GetSummary ( RolePermissions . Writer ) ;
101+ [ Test ]
102+ public async Task Should_summarize_the_writer_role_as_full_access ( )
103+ {
104+ var summary = await GetSummary ( RolePermissions . Writer ) ;
105105
106- using ( Assert . EnterMultipleScope ( ) )
107- {
108- Assert . That ( summary . FailedMessagesRead , Is . True ) ;
109- Assert . That ( summary . FailedMessagesWrite , Is . True ) ;
110- Assert . That ( summary . AuditingRead , Is . True ) ;
111- Assert . That ( summary . MonitoringRead , Is . True ) ;
112- Assert . That ( summary . MonitoringWrite , Is . True ) ;
113- Assert . That ( summary . AdminRead , Is . True ) ;
114- Assert . That ( summary . AdminWrite , Is . True ) ;
115- }
106+ using ( Assert . EnterMultipleScope ( ) )
107+ {
108+ Assert . That ( summary . FailedMessagesRead , Is . True ) ;
109+ Assert . That ( summary . FailedMessagesWrite , Is . True ) ;
110+ Assert . That ( summary . AuditingRead , Is . True ) ;
111+ Assert . That ( summary . MonitoringRead , Is . True ) ;
112+ Assert . That ( summary . MonitoringWrite , Is . True ) ;
113+ Assert . That ( summary . AdminRead , Is . True ) ;
114+ Assert . That ( summary . AdminWrite , Is . True ) ;
116115 }
116+ }
117117
118- [ Test ]
119- public async Task Should_summarize_a_role_with_no_grants_as_all_false ( )
120- {
121- // A role that exists on the token but isn't recognised by RolePermissions grants nothing.
122- var summary = await GetSummary ( "not-a-real-role" ) ;
118+ [ Test ]
119+ public async Task Should_summarize_a_role_with_no_grants_as_all_false ( )
120+ {
121+ // A role that exists on the token but isn't recognised by RolePermissions grants nothing.
122+ var summary = await GetSummary ( "not-a-real-role" ) ;
123123
124- using ( Assert . EnterMultipleScope ( ) )
125- {
126- Assert . That ( summary . FailedMessagesRead , Is . False ) ;
127- Assert . That ( summary . FailedMessagesWrite , Is . False ) ;
128- Assert . That ( summary . AuditingRead , Is . False ) ;
129- Assert . That ( summary . MonitoringRead , Is . False ) ;
130- Assert . That ( summary . MonitoringWrite , Is . False ) ;
131- Assert . That ( summary . AdminRead , Is . False ) ;
132- Assert . That ( summary . AdminWrite , Is . False ) ;
133- }
124+ using ( Assert . EnterMultipleScope ( ) )
125+ {
126+ Assert . That ( summary . FailedMessagesRead , Is . False ) ;
127+ Assert . That ( summary . FailedMessagesWrite , Is . False ) ;
128+ Assert . That ( summary . AuditingRead , Is . False ) ;
129+ Assert . That ( summary . MonitoringRead , Is . False ) ;
130+ Assert . That ( summary . MonitoringWrite , Is . False ) ;
131+ Assert . That ( summary . AdminRead , Is . False ) ;
132+ Assert . That ( summary . AdminWrite , Is . False ) ;
134133 }
134+ }
135135
136- async Task < MeController . PermissionsDescriptor > GetPermissions ( string role ) =>
137- await Get < MeController . PermissionsDescriptor > ( "/api/my/permissions/all" , role ) ;
136+ async Task < MeController . PermissionsDescriptor > GetPermissions ( string role ) =>
137+ await Get < MeController . PermissionsDescriptor > ( "/api/my/permissions/all" , role ) ;
138138
139- async Task < MeController . PermissionsSummary > GetSummary ( string role ) =>
140- await Get < MeController . PermissionsSummary > ( "/api/my/permissions" , role ) ;
139+ async Task < MeController . PermissionsSummary > GetSummary ( string role ) =>
140+ await Get < MeController . PermissionsSummary > ( "/api/my/permissions" , role ) ;
141141
142- async Task < T > Get < T > ( string path , string role )
143- {
144- HttpResponseMessage response = null ;
145-
146- _ = await Define < Context > ( )
147- . Done ( async ctx =>
148- {
149- var token = mockOidcServer . GenerateToken ( additionalClaims : [ new Claim ( "roles" , role ) ] ) ;
150- response = await OpenIdConnectAssertions . SendRequestWithBearerToken (
151- HttpClient ,
152- HttpMethod . Get ,
153- path ,
154- token ) ;
155- return response != null ;
156- } )
157- . Run ( ) ;
158-
159- OpenIdConnectAssertions . AssertAuthenticated ( response ) ;
160-
161- var content = await response . Content . ReadAsStringAsync ( ) ;
162- return JsonSerializer . Deserialize < T > ( content , SerializerOptions ) ;
163- }
142+ async Task < T > Get < T > ( string path , string role )
143+ {
144+ HttpResponseMessage response = null ;
164145
165- class Context : ScenarioContext ;
146+ _ = await Define < Context > ( )
147+ . Done ( async ctx =>
148+ {
149+ var token = mockOidcServer . GenerateToken ( additionalClaims : [ new Claim ( "roles" , role ) ] ) ;
150+ response = await OpenIdConnectAssertions . SendRequestWithBearerToken (
151+ HttpClient ,
152+ HttpMethod . Get ,
153+ path ,
154+ token ) ;
155+ return response != null ;
156+ } )
157+ . Run ( ) ;
158+
159+ OpenIdConnectAssertions . AssertAuthenticated ( response ) ;
160+
161+ var content = await response . Content . ReadAsStringAsync ( ) ;
162+ return JsonSerializer . Deserialize < T > ( content , SerializerOptions ) ;
166163 }
164+
165+ class Context : ScenarioContext ;
167166}
0 commit comments