@@ -203,7 +203,7 @@ protected String getClassName(IAuthorizationPlugin plugin) {
203
203
*
204
204
* @return the stack containing plugins/other stacks
205
205
*/
206
- protected synchronized AuthorizationStack getStack () {
206
+ public synchronized AuthorizationStack getStack () {
207
207
return stack ;
208
208
}
209
209
@@ -212,29 +212,31 @@ protected synchronized AuthorizationStack getStack() {
212
212
*
213
213
* @param s new stack to be used
214
214
*/
215
- protected synchronized void setStack (AuthorizationStack s ) {
215
+ public synchronized void setStack (AuthorizationStack s ) {
216
216
this .stack = s ;
217
217
}
218
218
219
219
/**
220
220
* Add an entity into the plugin stack.
221
221
*
222
+ * @param stack the stack
222
223
* @param entity the authorization entity (stack or plugin)
223
224
*/
224
- protected synchronized void addPlugin (AuthorizationEntity entity ) {
225
+ protected void addPlugin (AuthorizationStack stack , AuthorizationEntity entity ) {
225
226
if (stack != null ) {
226
227
stack .add (entity );
227
228
}
228
229
}
229
230
230
231
/**
231
232
* Add a plugin into the plugin stack. This has the same effect as invoking
232
- * addPlugin(IAuthorizationPlugin, REQUIRED).
233
+ * addPlugin(stack, IAuthorizationPlugin, REQUIRED).
233
234
*
235
+ * @param stack the stack
234
236
* @param plugin the authorization plugin
235
237
*/
236
- public synchronized void addPlugin (IAuthorizationPlugin plugin ) {
237
- addPlugin (plugin , AuthControlFlag .REQUIRED );
238
+ public void addPlugin (AuthorizationStack stack , IAuthorizationPlugin plugin ) {
239
+ addPlugin (stack , plugin , AuthControlFlag .REQUIRED );
238
240
}
239
241
240
242
/**
@@ -252,44 +254,49 @@ public synchronized void addPlugin(IAuthorizationPlugin plugin) {
252
254
* <b>The plugin's load method is NOT invoked at this point</b></p>
253
255
*
254
256
* This has the same effect as invoking addPlugin(new
255
- * AuthorizationEntity(flag, getClassName(plugin), plugin).
257
+ * AuthorizationEntity(stack, flag, getClassName(plugin), plugin).
256
258
*
259
+ * @param stack the stack
257
260
* @param plugin the authorization plugin
258
261
* @param flag the flag for the new plugin
259
262
*/
260
- public synchronized void addPlugin (IAuthorizationPlugin plugin , AuthControlFlag flag ) {
263
+ public void addPlugin (AuthorizationStack stack , IAuthorizationPlugin plugin , AuthControlFlag flag ) {
261
264
if (stack != null ) {
262
265
LOGGER .log (Level .INFO , "Plugin class \" {0}\" was not found in configuration."
263
266
+ " Appending the plugin at the end of the list with flag \" {1}\" " ,
264
267
new Object []{getClassName (plugin ), flag });
265
- addPlugin (new AuthorizationPlugin (flag , getClassName (plugin ), plugin ));
268
+ addPlugin (stack , new AuthorizationPlugin (flag , getClassName (plugin ), plugin ));
266
269
}
267
270
}
268
271
269
272
/**
270
- * Remove and unload all plugins.
273
+ * Remove and unload all plugins from the stack .
271
274
*
275
+ * @param stack the stack
272
276
* @see AuthorizationEntity#unload()
273
277
*/
274
- public synchronized void removeAll () {
275
- unloadAllPlugins ();
276
- stack = RuntimeEnvironment .getInstance ().getPluginStack ();
278
+ public void removeAll (AuthorizationStack stack ) {
279
+ unloadAllPlugins (stack );
277
280
}
278
281
279
282
/**
280
- * Load all plugins. If any plugin has not been loaded yet it is marked as
281
- * failed.
283
+ * Load all plugins in the stack. If any plugin has not been loaded yet it
284
+ * is marked as failed.
285
+ *
286
+ * @param stack the stack
282
287
*/
283
- public synchronized void loadAllPlugins () {
288
+ public void loadAllPlugins (AuthorizationStack stack ) {
284
289
if (stack != null ) {
285
290
stack .load (new TreeMap <>());
286
291
}
287
292
}
288
293
289
294
/**
290
- * Unload all plugins
295
+ * Unload all plugins in the stack
296
+ *
297
+ * @param stack the stack
291
298
*/
292
- public synchronized void unloadAllPlugins () {
299
+ public void unloadAllPlugins (AuthorizationStack stack ) {
293
300
if (stack != null ) {
294
301
stack .unload ();
295
302
}
@@ -363,17 +370,18 @@ private IAuthorizationPlugin loadClass(String classname) throws ClassNotFoundExc
363
370
/**
364
371
* Traverse list of files which possibly contain a java class and then
365
372
* traverse a list of jar files to load all classes which are contained
366
- * within them. Each class is loaded with {@link #handleLoadClass(String)}
367
- * which delegates the loading to the custom class loader
368
- * {@link #loadClass(String)}.
373
+ * within them into the given stack . Each class is loaded with
374
+ * {@link #handleLoadClass(String)} which delegates the loading to the
375
+ * custom class loader {@link #loadClass(String)}.
369
376
*
377
+ * @param stack the stack where to add the loaded classes
370
378
* @param classfiles list of files which possibly contain a java class
371
379
* @param jarfiles list of jar files containing java classes
372
380
*
373
381
* @see #handleLoadClass(String)
374
382
* @see #loadClass(String)
375
383
*/
376
- private void loadClasses (List <File > classfiles , List <File > jarfiles ) {
384
+ private void loadClasses (AuthorizationStack stack , List <File > classfiles , List <File > jarfiles ) {
377
385
IAuthorizationPlugin pf ;
378
386
for (File file : classfiles ) {
379
387
String classname = getClassName (file );
@@ -383,7 +391,7 @@ private void loadClasses(List<File> classfiles, List<File> jarfiles) {
383
391
// load the class in memory and try to find a configured space for this class
384
392
if ((pf = handleLoadClass (classname )) != null && !stack .setPlugin (pf )) {
385
393
// if there is not configured space -> append it to the stack
386
- addPlugin (pf );
394
+ addPlugin (stack , pf );
387
395
}
388
396
}
389
397
@@ -399,7 +407,7 @@ private void loadClasses(List<File> classfiles, List<File> jarfiles) {
399
407
// load the class in memory and try to find a configured space for this class
400
408
if ((pf = handleLoadClass (classname )) != null && !stack .setPlugin (pf )) {
401
409
// if there is not configured space -> append it to the stack
402
- addPlugin (pf );
410
+ addPlugin (stack , pf );
403
411
}
404
412
}
405
413
} catch (IOException ex ) {
@@ -433,7 +441,7 @@ private String getClassName(JarEntry f) {
433
441
* @see Configuration#getPluginDirectory()
434
442
*/
435
443
@ SuppressWarnings ("unchecked" )
436
- public synchronized void reload () {
444
+ public void reload () {
437
445
if (pluginDirectory == null || !pluginDirectory .isDirectory () || !pluginDirectory .canRead ()) {
438
446
LOGGER .log (Level .WARNING , "Plugin directory not found or not readable: {0}. "
439
447
+ "All requests allowed." , pluginDirectory );
@@ -455,22 +463,35 @@ public Object run() {
455
463
}
456
464
});
457
465
458
- // clean the stack
459
- removeAll ();
466
+ // clone a new stack not interfering with the current stack
467
+ AuthorizationStack newStack = RuntimeEnvironment . getInstance (). getPluginStack (). clone ();
460
468
461
469
// increase the current plugin version tracked by the framework
462
470
increasePluginVersion ();
463
471
464
- // refresh the current configuration if there was any change
465
- stack = RuntimeEnvironment .getInstance ().getPluginStack ();
466
-
467
472
// load all other possible plugin classes
468
- loadClasses (
473
+ loadClasses (newStack ,
469
474
IOUtils .listFilesRec (pluginDirectory , ".class" ),
470
475
IOUtils .listFiles (pluginDirectory , ".jar" ));
471
476
472
477
// fire load events
473
- loadAllPlugins ();
478
+ loadAllPlugins (newStack );
479
+
480
+ /**
481
+ * Replace the stack in a synchronized block to avoid inconsistent state
482
+ * between the stack change and currently executing requests performing
483
+ * some authorization on the same stack.
484
+ *
485
+ * @see #performCheck is also marked as synchronized
486
+ */
487
+ AuthorizationStack oldStack = stack ;
488
+ synchronized (this ) {
489
+ stack = newStack ;
490
+ }
491
+
492
+ // clean the old stack
493
+ removeAll (oldStack );
494
+ oldStack = null ;
474
495
}
475
496
476
497
/**
@@ -578,7 +599,15 @@ private boolean checkAll(HttpServletRequest request, String cache, Nameable enti
578
599
return overallDecision ;
579
600
}
580
601
581
- private boolean performCheck (Nameable entity , Predicate <IAuthorizationPlugin > predicate ) {
602
+ /**
603
+ * Perform the actual check for the entity.
604
+ *
605
+ * @param entity either a project or a group
606
+ * @param predicate a predicate that decides if the authorization is
607
+ * successful for the given plugin
608
+ * @return true if entity is allowed; false otherwise
609
+ */
610
+ private synchronized boolean performCheck (Nameable entity , Predicate <IAuthorizationPlugin > predicate ) {
582
611
return stack .isAllowed (entity , predicate );
583
612
}
584
613
}
0 commit comments