1
+ /**
2
+ * Copyright since 2016 by Ortus Solutions, Corp
3
+ * www.ortussolutions.com
4
+ * ---
5
+ * This service is in charge of offering security capabilties to your ColdBox applications
6
+ *
7
+ * It can be injected by using the `@cbSecurity` annotation
8
+ *
9
+ * <pre >
10
+ * property name="cbSecurity" inject="@cbsecurity";
11
+ * </pre>
12
+ *
13
+ * Or you can use the `cbSecure()` mixin
14
+ *
15
+ * <pre >
16
+ * cbsecure().secure();
17
+ * </pre>
18
+ */
19
+ component singleton accessors = " true" {
20
+
21
+ /* ********************************************************************************************/
22
+ /* * DI **/
23
+ /* ********************************************************************************************/
24
+
25
+ property name = " settings" inject = " coldbox:moduleSettings:cbsecurity" ;
26
+ property name = " log" inject = " logbox:logger:{this}" ;
27
+ property name = " wirebox" inject = " wirebox" ;
28
+
29
+
30
+ /* ********************************************************************************************/
31
+ /* * PROPERTIES **/
32
+ /* ********************************************************************************************/
33
+
34
+ /**
35
+ * The auth service in use according to the configuration file
36
+ */
37
+ property name = " authService" ;
38
+
39
+ /**
40
+ * The user service in use according to the configuration file
41
+ */
42
+ property name = " userService" ;
43
+
44
+ /* ********************************************************************************************/
45
+ /* * Static Vars **/
46
+ /* ********************************************************************************************/
47
+
48
+ variables .DEFAULT_ERROR_MESSAGE = " Not authorized!" ;
49
+
50
+ /**
51
+ * Constructor
52
+ */
53
+ function init (){
54
+ return this ;
55
+ }
56
+
57
+ /**
58
+ * Get the user service object defined accordingly in the settings
59
+ *
60
+ * @throws IncompleteConfiguration
61
+ *
62
+ * @return cbsecurity.interfaces.IUserService
63
+ */
64
+ any function getUserService (){
65
+ // If loaded, use it!
66
+ if ( ! isNull ( variables .userService ) ) {
67
+ return variables .userService ;
68
+ }
69
+
70
+ // Check and Load Baby!
71
+ if ( ! len ( variables .settings .userService ) ) {
72
+ throw (
73
+ message = " No [userService] provided in the settings. Please set it in the `config/ColdBox.cfc` under `moduleSettings.cbsecurity.userService`." ,
74
+ type = " IncompleteConfiguration"
75
+ );
76
+ }
77
+
78
+ return variables .userService = variables .wirebox .getInstance ( variables .settings .userService );
79
+ }
80
+
81
+ /**
82
+ * Get the authentication service defined accordingly in the settings
83
+ *
84
+ * @throws IncompleteConfiguration
85
+ *
86
+ * @return cbsecurity.interfaces.IAuthService
87
+ */
88
+ any function getAuthService (){
89
+ // If loaded, use it!
90
+ if ( ! isNull ( variables .authService ) ) {
91
+ return variables .authService ;
92
+ }
93
+
94
+ // Check and Load Baby!
95
+ if ( ! len ( variables .settings .authenticationService ) ) {
96
+ throw (
97
+ message = " No [authService] provided in the settings. Please set in `config/ColdBox.cfc` under `moduleSettings.cbsecurity.authenticationService`." ,
98
+ type = " IncompleteConfiguration"
99
+ );
100
+ }
101
+
102
+ return variables .authService = variables .wirebox .getInstance ( variables .settings .authenticationService );
103
+ }
104
+
105
+ /* **************************************************************/
106
+ /* Verification Methods
107
+ /***************************************************************/
108
+
109
+ /**
110
+ * Verify if the incoming permissions exist in the currently authenticated user.
111
+ * All permissions are Or'ed together
112
+ *
113
+ * @throws NoUserLoggedIn
114
+ *
115
+ * @permissions One, a list or an array of permissions
116
+ */
117
+ boolean function has ( required permissions ){
118
+ var oUser = getAuthService ().getUser ();
119
+
120
+ return arrayWrap ( arguments .permissions )
121
+ .filter ( function ( item ){
122
+ return oUser .hasPermission ( arguments .item );
123
+ } ).len () > 0 ;
124
+ }
125
+
126
+ /**
127
+ * Verify that ALL the permissions passed must exist within the authenticated user
128
+ *
129
+ * @throws NoUserLoggedIn
130
+ *
131
+ * @permissions One, a list or an array of permissions
132
+ */
133
+ boolean function all ( required permissions ){
134
+ var oUser = getAuthService ().getUser ();
135
+ var aPerms = arrayWrap ( arguments .permissions );
136
+
137
+ return aPerms
138
+ .filter ( function ( item ){
139
+ return oUser .hasPermission ( arguments .item );
140
+ } ).len () == aPerms .len ();
141
+ }
142
+
143
+ /**
144
+ * Verify that NONE of the permissions passed must exist within the authenticated user
145
+ *
146
+ * @throws NoUserLoggedIn
147
+ *
148
+ * @permissions One, a list or an array of permissions
149
+ */
150
+ boolean function none ( required permissions ){
151
+ var oUser = getAuthService ().getUser ();
152
+
153
+ return arrayWrap ( arguments .permissions )
154
+ .filter ( function ( item ){
155
+ return oUser .hasPermission ( arguments .item );
156
+ } ).len () == 0 ;
157
+ }
158
+
159
+ /**
160
+ * Verify that the passed in user object must be the same as the authenticated user
161
+ * Equality is done by evaluating the `getid()` method on both objects.
162
+ *
163
+ * @throws NoUserLoggedIn
164
+ *
165
+ * @user The user to test for equality
166
+ */
167
+ boolean function sameUser ( required user ){
168
+ return ( arguments .user .getId () == getAuthService ().getUser ().getId () );
169
+ }
170
+
171
+ /* **************************************************************/
172
+ /* Blocking Methods
173
+ /***************************************************************/
174
+
175
+ /**
176
+ * Verifies if the currently logged in user has any of the passed permissions.
177
+ *
178
+ * @throws NotAuthorized
179
+ *
180
+ * @permissions One, a list or an array of permissions
181
+ * @message The error message to throw in the exception
182
+ *
183
+ * @return s CBSecurity
184
+ */
185
+ CBSecurity function secure ( required permissions , message = variables .DEFAULT_ERROR_MESSAGE ){
186
+ if ( ! has ( arguments .permissions ) ){
187
+ throw ( type = " NotAuthorized" , message = arguments .message );
188
+ }
189
+ return this ;
190
+ }
191
+
192
+ /**
193
+ * Verifies if the currently logged in user has ALL of the passed permissions.
194
+ *
195
+ * @throws NotAuthorized
196
+ *
197
+ * @permissions One, a list or an array of permissions
198
+ * @message The error message to throw in the exception
199
+ *
200
+ * @return s CBSecurity
201
+ */
202
+ CBSecurity function secureAll ( required permissions , message = variables .DEFAULT_ERROR_MESSAGE ){
203
+ if ( ! all ( arguments .permissions ) ){
204
+ throw ( type = " NotAuthorized" , message = arguments .message );
205
+ }
206
+ return this ;
207
+ }
208
+
209
+ /**
210
+ * Verifies if the currently logged in user has NONE of the passed permissions.
211
+ *
212
+ * @throws NotAuthorized
213
+ *
214
+ * @permissions One, a list or an array of permissions
215
+ * @message The error message to throw in the exception
216
+ *
217
+ * @return s CBSecurity
218
+ */
219
+ CBSecurity function secureNone ( required permissions , message = variables .DEFAULT_ERROR_MESSAGE ){
220
+ if ( ! none ( arguments .permissions ) ){
221
+ throw ( type = " NotAuthorized" , message = arguments .message );
222
+ }
223
+ return this ;
224
+ }
225
+
226
+ /**
227
+ * Verifies the passed in context closure/lambda/udf to a boolean expression.
228
+ * If the context is true, then the exception is thrown. The context must be false in order to pass.
229
+ *
230
+ * The context udf/closure/lambda must adhere to the following signature
231
+ *
232
+ * <pre >
233
+ * function( user ){}
234
+ * ( user ) => {}
235
+ * </pre>
236
+ *
237
+ * It receives the currently logged in user
238
+ *
239
+ * @throws NotAuthorized
240
+ *
241
+ * @context A closure/lambda/udf that returns boolean, or a boolean expression
242
+ * @message The error message to throw in the exception
243
+ *
244
+ * @return s CBSecurity
245
+ */
246
+ CBSecurity function secureWhen ( required context , message = variables .DEFAULT_ERROR_MESSAGE ){
247
+ var results = arguments .context ;
248
+ // Check if udf/lambda
249
+ if ( isCustomFunction ( arguments .context ) || isClosure ( arguments .context ) ){
250
+ results = arguments .context ( getAuthService ().getUser () );
251
+ }
252
+ if ( results ){
253
+ throw ( type = " NotAuthorized" , message = arguments .message );
254
+ }
255
+ return this ;
256
+ }
257
+
258
+ /**
259
+ * Alias proxy if somebody is coming from cbguard, proxies to the secure() method
260
+ */
261
+ function guard (){
262
+ return secure ( argumentCollection = arguments );
263
+ }
264
+
265
+ /* **************************************************************/
266
+ /* Action Context Methods
267
+ /***************************************************************/
268
+
269
+ /**
270
+ * This method will verify that any permissions must exist in the currently logged in user.
271
+ *
272
+ * - If the result is true, then it will execute the success closure/lambda or udf.
273
+ * - If the restul is false, then it will execute the fail closure/lambda or udf
274
+ *
275
+ * The success or fail closures/lambdas/udfs must match the following signature
276
+ *
277
+ * <pre >
278
+ * function( user, permissions ){}
279
+ * ( user, permissions ) => {}
280
+ * </pre>
281
+ *
282
+ * They receive the currently logged in user and the permissions that where evaluated
283
+ *
284
+ * @permissions One, a list or an array of permissions
285
+ * @success The closure/lambda/udf that executes if the context passes
286
+ * @fail The closure/lambda/udf that executes if the context fails
287
+ */
288
+ function when ( required permissions , required success , fail ){
289
+
290
+ }
291
+
292
+ /**
293
+ * This method will verify that ALL permissions must exist in the currently logged in user.
294
+ *
295
+ * - If the result is true, then it will execute the success closure/lambda or udf.
296
+ * - If the restul is false, then it will execute the fail closure/lambda or udf
297
+ *
298
+ * The success or fail closures/lambdas/udfs must match the following signature
299
+ *
300
+ * <pre >
301
+ * function( user, permissions ){}
302
+ * ( user, permissions ) => {}
303
+ * </pre>
304
+ *
305
+ * They receive the currently logged in user and the permissions that where evaluated
306
+ *
307
+ * @permissions One, a list or an array of permissions
308
+ * @success The closure/lambda/udf that executes if the context passes
309
+ * @fail The closure/lambda/udf that executes if the context fails
310
+ */
311
+ function whenAll ( required permissions , required success , fail ){
312
+
313
+ }
314
+
315
+ /**
316
+ * This method will verify that NONE of the permissions must exist in the currently logged in user.
317
+ *
318
+ * - If the result is true, then it will execute the success closure/lambda or udf.
319
+ * - If the restul is false, then it will execute the fail closure/lambda or udf
320
+ *
321
+ * The success or fail closures/lambdas/udfs must match the following signature
322
+ *
323
+ * <pre >
324
+ * function( user, permissions ){}
325
+ * ( user, permissions ) => {}
326
+ * </pre>
327
+ *
328
+ * They receive the currently logged in user and the permissions that where evaluated
329
+ *
330
+ * @permissions One, a list or an array of permissions
331
+ * @success The closure/lambda/udf that executes if the context passes
332
+ * @fail The closure/lambda/udf that executes if the context fails
333
+ */
334
+ function whenNone ( required permissions , required success , fail ){
335
+
336
+ }
337
+
338
+ /* **************************************************************/
339
+ /* Private Methods
340
+ /***************************************************************/
341
+
342
+ /**
343
+ * convert one or a list of permissions to an array, if it's an array we don't touch it
344
+ *
345
+ * @items One, a list or an array
346
+ */
347
+ private function arrayWrap ( required items ){
348
+ return isArray ( arguments .items ) ? items : items .listToArray ();
349
+ }
350
+
351
+ }
0 commit comments