|
19 | 19 | import java.util.HashSet; |
20 | 20 | import java.util.List; |
21 | 21 | import java.util.Map; |
| 22 | +import java.util.Objects; |
22 | 23 | import java.util.Set; |
23 | 24 | import java.util.concurrent.Executor; |
24 | 25 | import java.util.concurrent.ExecutorService; |
@@ -294,16 +295,24 @@ public ChannelBuilder withRoles(Role... roles) { |
294 | 295 | * @since 2.47 |
295 | 296 | */ |
296 | 297 | public ChannelBuilder withRoles(final Collection<? extends Role> actual) { |
297 | | - return withRoleChecker(new RoleChecker() { |
298 | | - @Override |
299 | | - public void check(@NonNull RoleSensitive subject, @NonNull Collection<Role> expected) { |
300 | | - if (!actual.containsAll(expected)) { |
301 | | - Collection<Role> c = new ArrayList<>(expected); |
302 | | - c.removeAll(actual); |
303 | | - throw new SecurityException("Unexpected role: " + c); |
304 | | - } |
| 298 | + return withRoleChecker(new RoleCheckerImpl(actual)); |
| 299 | + } |
| 300 | + |
| 301 | + private static class RoleCheckerImpl extends RoleChecker { |
| 302 | + private final Collection<? extends Role> actual; |
| 303 | + |
| 304 | + public RoleCheckerImpl(Collection<? extends Role> actual) { |
| 305 | + this.actual = Objects.requireNonNull(actual); |
| 306 | + } |
| 307 | + |
| 308 | + @Override |
| 309 | + public void check(@NonNull RoleSensitive subject, @NonNull Collection<Role> expected) { |
| 310 | + if (!actual.containsAll(expected)) { |
| 311 | + Collection<Role> c = new ArrayList<>(expected); |
| 312 | + c.removeAll(actual); |
| 313 | + throw new SecurityException("Unexpected role: " + c); |
305 | 314 | } |
306 | | - }); |
| 315 | + } |
307 | 316 | } |
308 | 317 |
|
309 | 318 | private static boolean isCallableProhibitedByRequiredRoleCheck(Callable<?, ?> callable) { |
@@ -332,32 +341,38 @@ private static boolean isCallableProhibitedByRequiredRoleCheck(Callable<?, ?> ca |
332 | 341 | * @since 2.47 |
333 | 342 | */ |
334 | 343 | public ChannelBuilder withRoleChecker(final RoleChecker checker) { |
335 | | - return with(new CallableDecorator() { |
336 | | - @Override |
337 | | - public <V, T extends Throwable> Callable<V, T> userRequest(Callable<V, T> op, Callable<V, T> stem) { |
338 | | - try { |
339 | | - RequiredRoleCheckerWrapper wrapped = new RequiredRoleCheckerWrapper(checker); |
340 | | - stem.checkRoles(wrapped); |
341 | | - if (wrapped.isChecked()) { |
342 | | - LOGGER.log( |
343 | | - Level.FINER, () -> "Callable " + stem.getClass().getName() + " checked roles"); |
344 | | - } else if (isCallableProhibitedByRequiredRoleCheck(stem)) { |
345 | | - LOGGER.log( |
346 | | - Level.INFO, |
347 | | - () -> "Rejecting callable " + stem.getClass().getName() |
348 | | - + " for ignoring RoleChecker in #checkRoles, see https://www.jenkins.io/redirect/required-role-check"); |
349 | | - throw new SecurityException( |
350 | | - "Security hardening prohibits the Callable implementation " |
351 | | - + stem.getClass().getName() |
352 | | - + " from ignoring RoleChecker, see https://www.jenkins.io/redirect/required-role-check"); |
353 | | - } |
354 | | - } catch (AbstractMethodError e) { |
355 | | - checker.check(stem, Role.UNKNOWN); // not implemented, assume 'unknown' |
356 | | - } |
| 344 | + return with(new CallableDecoratorImpl(checker)); |
| 345 | + } |
| 346 | + |
| 347 | + private static class CallableDecoratorImpl extends CallableDecorator { |
| 348 | + private final RoleChecker checker; |
| 349 | + |
| 350 | + public CallableDecoratorImpl(RoleChecker checker) { |
| 351 | + this.checker = Objects.requireNonNull(checker); |
| 352 | + } |
357 | 353 |
|
358 | | - return stem; |
| 354 | + @Override |
| 355 | + public <V, T extends Throwable> Callable<V, T> userRequest(Callable<V, T> op, Callable<V, T> stem) { |
| 356 | + try { |
| 357 | + RequiredRoleCheckerWrapper wrapped = new RequiredRoleCheckerWrapper(checker); |
| 358 | + stem.checkRoles(wrapped); |
| 359 | + if (wrapped.isChecked()) { |
| 360 | + LOGGER.log(Level.FINER, () -> "Callable " + stem.getClass().getName() + " checked roles"); |
| 361 | + } else if (isCallableProhibitedByRequiredRoleCheck(stem)) { |
| 362 | + LOGGER.log( |
| 363 | + Level.INFO, |
| 364 | + () -> "Rejecting callable " + stem.getClass().getName() |
| 365 | + + " for ignoring RoleChecker in #checkRoles, see https://www.jenkins.io/redirect/required-role-check"); |
| 366 | + throw new SecurityException("Security hardening prohibits the Callable implementation " |
| 367 | + + stem.getClass().getName() |
| 368 | + + " from ignoring RoleChecker, see https://www.jenkins.io/redirect/required-role-check"); |
| 369 | + } |
| 370 | + } catch (AbstractMethodError e) { |
| 371 | + checker.check(stem, Role.UNKNOWN); // not implemented, assume 'unknown' |
359 | 372 | } |
360 | | - }); |
| 373 | + |
| 374 | + return stem; |
| 375 | + } |
361 | 376 | } |
362 | 377 |
|
363 | 378 | /** |
|
0 commit comments