6
6
using System . Collections . Generic ;
7
7
using System . Linq ;
8
8
using System . Net . Http ;
9
+ using System . Text . RegularExpressions ;
9
10
using System . Threading . Tasks ;
10
11
11
12
namespace FoxIDs . Infrastructure . Security
12
13
{
13
14
public abstract class BaseAuthorizationRequirement < Tar , Tsc > : AuthorizationHandler < Tar > , IAuthorizationRequirement where Tar : IAuthorizationRequirement where Tsc : BaseScopeAuthorizeAttribute
14
15
{
16
+ private static Regex accessToTracksRegex = new Regex ( @"((?::track\[(?<track>[\w-]+)\])|(?::track\[(?<trackget>[\w-]+)\].read)|(?::track\[(?<trackpost>[\w-]+)\].create)|(?::track\[(?<trackput>[\w-]+)\].update)|(?::track\[(?<trackdelete>[\w-]+)\].delete))$" , RegexOptions . Compiled ) ;
17
+ protected bool supportAccessToTracks = false ;
18
+
15
19
protected override Task HandleRequirementAsync ( AuthorizationHandlerContext context , Tar requirement )
16
20
{
17
21
if ( context . User != null && context . Resource is HttpContext httpContext )
@@ -31,10 +35,12 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte
31
35
var userRoles = context . User . Claims . Where ( c => string . Equals ( c . Type , JwtClaimTypes . Role , StringComparison . OrdinalIgnoreCase ) ) . Select ( c => c . Value ) . ToList ( ) ;
32
36
if ( userScopes ? . Count ( ) > 0 && userRoles ? . Count > 0 )
33
37
{
34
- ( var acceptedScopes , var acceptedRoles ) = GetAcceptedScopesAndRoles ( scopeAuthorizeAttribute . Segments , httpContext . GetRouteBinding ( ) . TrackName , httpContext . Request ? . Method ) ;
38
+ var accessToTrackNames = GetAccessToTracks ( userScopes , userRoles , httpContext . Request ? . Method ) ;
39
+ ( var acceptedScopes , var acceptedRoles ) = GetAcceptedScopesAndRoles ( scopeAuthorizeAttribute . Segments , httpContext . GetRouteBinding ( ) . TrackName , httpContext . Request ? . Method , accessToTrackNames ) ;
35
40
36
41
if ( userScopes . Where ( us => acceptedScopes . Any ( s => s . Equals ( us , StringComparison . Ordinal ) ) ) . Any ( ) && userRoles . Where ( ur => acceptedRoles . Any ( r => r . Equals ( ur , StringComparison . Ordinal ) ) ) . Any ( ) )
37
42
{
43
+ AddAccessToTracksRequestItems ( httpContext , userScopes . Where ( us => acceptedScopes . Any ( s => s . Equals ( us , StringComparison . Ordinal ) ) ) , userRoles . Where ( ur => acceptedRoles . Any ( r => r . Equals ( ur , StringComparison . Ordinal ) ) ) , httpContext . Request ? . Method ) ;
38
44
context . Succeed ( requirement ) ;
39
45
}
40
46
else
@@ -60,7 +66,7 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte
60
66
return Task . CompletedTask ;
61
67
}
62
68
63
- protected abstract ( List < string > acceptedScopes , List < string > acceptedRoles ) GetAcceptedScopesAndRoles ( IEnumerable < string > segments , string trackName , string httpMethod ) ;
69
+ protected abstract ( List < string > acceptedScopes , List < string > acceptedRoles ) GetAcceptedScopesAndRoles ( IEnumerable < string > segments , string trackName , string httpMethod , IEnumerable < string > accessToTrackNames = null ) ;
64
70
65
71
protected void AddScopeAndRole ( List < string > acceptedScopes , List < string > acceptedRoles , string httpMethod , string scope , string role , string segment = "" )
66
72
{
@@ -93,5 +99,106 @@ protected void AddScopeAndRole(List<string> acceptedScopes, List<string> accepte
93
99
}
94
100
}
95
101
}
102
+
103
+ private IEnumerable < string > GetAccessToTracks ( IEnumerable < string > userScopes , IEnumerable < string > userRoles , string httpMethod )
104
+ {
105
+ if ( ! supportAccessToTracks )
106
+ {
107
+ return null ;
108
+ }
109
+
110
+ var accessToTrackNames = new List < string > ( ) ;
111
+ accessToTrackNames . AddRange ( GetAccessToTracks ( userScopes , httpMethod ) ) ;
112
+ accessToTrackNames . ConcatOnce ( GetAccessToTracks ( userRoles , httpMethod ) ) ;
113
+ return accessToTrackNames ;
114
+ }
115
+
116
+ private IEnumerable < string > GetAccessToTracks ( IEnumerable < string > userScopesOrRole , string httpMethod )
117
+ {
118
+ foreach ( var item in userScopesOrRole )
119
+ {
120
+ var itemMatch = accessToTracksRegex . Match ( item ) ;
121
+ if ( itemMatch . Success )
122
+ {
123
+ if ( itemMatch . Groups [ "track" ] . Success )
124
+ {
125
+ yield return itemMatch . Groups [ "track" ] . Value ;
126
+ }
127
+
128
+ if ( httpMethod == HttpMethod . Get . Method )
129
+ {
130
+ if ( itemMatch . Groups [ "trackget" ] . Success )
131
+ {
132
+ yield return itemMatch . Groups [ "trackget" ] . Value ;
133
+ }
134
+ }
135
+ else if ( httpMethod == HttpMethod . Post . Method )
136
+ {
137
+ if ( itemMatch . Groups [ "trackpost" ] . Success )
138
+ {
139
+ yield return itemMatch . Groups [ "trackpost" ] . Value ;
140
+ }
141
+
142
+ }
143
+ else if ( httpMethod == HttpMethod . Put . Method )
144
+ {
145
+ if ( itemMatch . Groups [ "trackput" ] . Success )
146
+ {
147
+ yield return itemMatch . Groups [ "trackput" ] . Value ;
148
+ }
149
+
150
+ }
151
+ else if ( httpMethod == HttpMethod . Delete . Method )
152
+ {
153
+ if ( itemMatch . Groups [ "trackdelete" ] . Success )
154
+ {
155
+ yield return itemMatch . Groups [ "trackdelete" ] . Value ;
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ private void AddAccessToTracksRequestItems ( HttpContext httpContext , IEnumerable < string > accessUserScopes , IEnumerable < string > accessUserRoles , string httpMethod )
163
+ {
164
+ if ( ! supportAccessToTracks )
165
+ {
166
+ return ;
167
+ }
168
+
169
+ var scopesGrantAccessToAnyTrack = ! accessToTracksRegex . Match ( accessUserScopes . First ( ) ) . Success ;
170
+ var rolesGrantAccessToAnyTrack = ! accessToTracksRegex . Match ( accessUserRoles . First ( ) ) . Success ;
171
+
172
+ if ( scopesGrantAccessToAnyTrack && rolesGrantAccessToAnyTrack )
173
+ {
174
+ httpContext . Items [ Constants . ControlApi . AccessToAnyTrackKey ] = true ;
175
+ return ;
176
+ }
177
+
178
+ var scopesGrantAccessToTrackNames = GetAccessToTracks ( accessUserScopes , httpMethod ) ;
179
+ var rolesGrantAccessToTrackNames = GetAccessToTracks ( accessUserRoles , httpMethod ) ;
180
+
181
+ var accessToTracks = GetLimitedGrantedAccessToTracks ( scopesGrantAccessToAnyTrack , rolesGrantAccessToAnyTrack , scopesGrantAccessToTrackNames , rolesGrantAccessToTrackNames ) ;
182
+ if ( accessToTracks . Count ( ) > 0 )
183
+ {
184
+ httpContext . Items [ Constants . ControlApi . AccessToTrackNamesKey ] = accessToTracks ;
185
+ }
186
+ }
187
+
188
+ private IEnumerable < string > GetLimitedGrantedAccessToTracks ( bool scopesGrantAccessToAnyTrack , bool rolesGrantAccessToAnyTrack , IEnumerable < string > scopesGrantAccessToTrackNames , IEnumerable < string > rolesGrantAccessToTrackNames )
189
+ {
190
+ if ( scopesGrantAccessToAnyTrack )
191
+ {
192
+ return rolesGrantAccessToTrackNames ;
193
+ }
194
+ else if ( rolesGrantAccessToAnyTrack )
195
+ {
196
+ return scopesGrantAccessToTrackNames ;
197
+ }
198
+ else
199
+ {
200
+ return scopesGrantAccessToTrackNames . Where ( us => rolesGrantAccessToTrackNames . Any ( s => s . Equals ( us , StringComparison . Ordinal ) ) ) ;
201
+ }
202
+ }
96
203
}
97
204
}
0 commit comments