Skip to content

Commit 9cbcc3d

Browse files
authored
Fix SIC_INNER_SHOULD_BE_STATIC_ANON violations (#789)
1 parent 855b37f commit 9cbcc3d

File tree

6 files changed

+186
-146
lines changed

6 files changed

+186
-146
lines changed

src/main/java/hudson/remoting/AbstractByteArrayCommandTransport.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.ByteArrayOutputStream;
44
import java.io.IOException;
55
import java.io.ObjectOutputStream;
6+
import java.util.Objects;
67
import java.util.logging.Level;
78
import java.util.logging.Logger;
89
import org.jenkinsci.remoting.util.AnonymousClassWarnings;
@@ -56,22 +57,32 @@ public interface ByteArrayReceiver {
5657
@Override
5758
public final void setup(final Channel channel, final CommandReceiver receiver) {
5859
this.channel = channel;
59-
setup(new ByteArrayReceiver() {
60-
@Override
61-
public void handle(byte[] payload) {
62-
try {
63-
Command cmd = Command.readFrom(channel, payload);
64-
receiver.handle(cmd);
65-
} catch (IOException | ClassNotFoundException e) {
66-
LOGGER.log(Level.WARNING, "Failed to construct Command in channel " + channel.getName(), e);
67-
}
68-
}
60+
setup(new ByteArrayReceiverImpl(channel, receiver));
61+
}
62+
63+
private static class ByteArrayReceiverImpl implements ByteArrayReceiver {
64+
private final Channel channel;
65+
private final CommandReceiver receiver;
66+
67+
public ByteArrayReceiverImpl(Channel channel, CommandReceiver receiver) {
68+
this.channel = Objects.requireNonNull(channel);
69+
this.receiver = Objects.requireNonNull(receiver);
70+
}
6971

70-
@Override
71-
public void terminate(IOException e) {
72-
receiver.terminate(e);
72+
@Override
73+
public void handle(byte[] payload) {
74+
try {
75+
Command cmd = Command.readFrom(channel, payload);
76+
receiver.handle(cmd);
77+
} catch (IOException | ClassNotFoundException e) {
78+
LOGGER.log(Level.WARNING, "Failed to construct Command in channel " + channel.getName(), e);
7379
}
74-
});
80+
}
81+
82+
@Override
83+
public void terminate(IOException e) {
84+
receiver.terminate(e);
85+
}
7586
}
7687

7788
@Override

src/main/java/hudson/remoting/Capability.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -146,26 +146,32 @@ void writePreamble(OutputStream os) throws IOException {
146146
* Writes this capability to a stream.
147147
*/
148148
private void write(OutputStream os) throws IOException {
149-
try (ObjectOutputStream oos = new ObjectOutputStream(Channel.Mode.TEXT.wrap(os)) {
150-
@Override
151-
public void close() throws IOException {
152-
flush();
153-
// TODO: Cannot invoke the private clear() method, but GC well do it for us. Not worse than the original
154-
// solution
155-
// Here the code does not close the proxied stream OS on completion
156-
}
157-
158-
@Override
159-
protected void annotateClass(Class<?> c) throws IOException {
160-
AnonymousClassWarnings.check(c);
161-
super.annotateClass(c);
162-
}
163-
}) {
149+
try (ObjectOutputStream oos = new ObjectOutputStreamImpl(Channel.Mode.TEXT.wrap(os))) {
164150
oos.writeObject(this);
165151
oos.flush();
166152
}
167153
}
168154

155+
private static class ObjectOutputStreamImpl extends ObjectOutputStream {
156+
public ObjectOutputStreamImpl(OutputStream out) throws IOException {
157+
super(out);
158+
}
159+
160+
@Override
161+
public void close() throws IOException {
162+
flush();
163+
// TODO: Cannot invoke the private clear() method, but GC well do it for us. Not worse than the original
164+
// solution
165+
// Here the code does not close the proxied stream OS on completion
166+
}
167+
168+
@Override
169+
protected void annotateClass(Class<?> c) throws IOException {
170+
AnonymousClassWarnings.check(c);
171+
super.annotateClass(c);
172+
}
173+
}
174+
169175
/**
170176
* The opposite operation of {@link #write}.
171177
*/

src/main/java/hudson/remoting/ChannelBuilder.java

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.HashSet;
2020
import java.util.List;
2121
import java.util.Map;
22+
import java.util.Objects;
2223
import java.util.Set;
2324
import java.util.concurrent.Executor;
2425
import java.util.concurrent.ExecutorService;
@@ -294,16 +295,24 @@ public ChannelBuilder withRoles(Role... roles) {
294295
* @since 2.47
295296
*/
296297
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);
305314
}
306-
});
315+
}
307316
}
308317

309318
private static boolean isCallableProhibitedByRequiredRoleCheck(Callable<?, ?> callable) {
@@ -332,32 +341,38 @@ private static boolean isCallableProhibitedByRequiredRoleCheck(Callable<?, ?> ca
332341
* @since 2.47
333342
*/
334343
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+
}
357353

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'
359372
}
360-
});
373+
374+
return stem;
375+
}
361376
}
362377

363378
/**

src/main/java/hudson/remoting/LocalChannel.java

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
package hudson.remoting;
2525

2626
import edu.umd.cs.findbugs.annotations.NonNull;
27+
import java.util.Objects;
2728
import java.util.concurrent.ExecutionException;
2829
import java.util.concurrent.ExecutorService;
2930
import java.util.concurrent.TimeUnit;
@@ -58,33 +59,41 @@ public <V, T extends Throwable> Future<V> callAsync(@NonNull final Callable<V, T
5859
}
5960
});
6061

61-
return new Future<>() {
62-
@Override
63-
public boolean cancel(boolean mayInterruptIfRunning) {
64-
return f.cancel(mayInterruptIfRunning);
65-
}
62+
return new FutureImpl<>(f);
63+
}
6664

67-
@Override
68-
public boolean isCancelled() {
69-
return f.isCancelled();
70-
}
65+
private static class FutureImpl<V> implements Future<V> {
66+
private final java.util.concurrent.Future<V> f;
7167

72-
@Override
73-
public boolean isDone() {
74-
return f.isDone();
75-
}
68+
public FutureImpl(java.util.concurrent.Future<V> f) {
69+
this.f = Objects.requireNonNull(f);
70+
}
7671

77-
@Override
78-
public V get() throws InterruptedException, ExecutionException {
79-
return f.get();
80-
}
72+
@Override
73+
public boolean cancel(boolean mayInterruptIfRunning) {
74+
return f.cancel(mayInterruptIfRunning);
75+
}
8176

82-
@Override
83-
public V get(long timeout, @NonNull TimeUnit unit)
84-
throws InterruptedException, ExecutionException, TimeoutException {
85-
return f.get(timeout, unit);
86-
}
87-
};
77+
@Override
78+
public boolean isCancelled() {
79+
return f.isCancelled();
80+
}
81+
82+
@Override
83+
public boolean isDone() {
84+
return f.isDone();
85+
}
86+
87+
@Override
88+
public V get() throws InterruptedException, ExecutionException {
89+
return f.get();
90+
}
91+
92+
@Override
93+
public V get(long timeout, @NonNull TimeUnit unit)
94+
throws InterruptedException, ExecutionException, TimeoutException {
95+
return f.get(timeout, unit);
96+
}
8897
}
8998

9099
@Override

0 commit comments

Comments
 (0)