<commit_before>package hudson.remoting;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.*;

/**
 * @author <NAME>
 */
public class ClassFilterTest implements Serializable {

    /**
     * North can defend itself from south but not the other way around.
     */
    private transient InProcessRunner runner = new InProcessRunner() {
        @Override
        protected ChannelBuilder configureNorth() {
            return super.configureNorth()
                    .withClassFilter(new TestFilter());
        }
    };

    private transient Channel north, south;

    private static class TestFilter extends ClassFilter {
        @Override
        protected boolean isBlacklisted(String name) {
            if (name.contains("Security218"))
                return true;
            return false;
        }
    }

    /**
     * Set up a channel pair where french side is well protected by british side is not.
     */
    @Before
    public void setUp() throws Exception {
        north = runner.start();
        south = runner.south;
        ATTACKS.clear();
    }

    @After
    public void tearDown() throws Exception {
        runner.stop(north);
    }

    @Test
    public void successful_defense() throws Exception {
        try {
            final Security218 a = new Security218("napoleon");
            south.call(new CallableBase<Void, IOException>() {
                @Override
                public Void call() throws IOException {
                    a.toString();   // this will ensure 'a' gets sent over
                    return null;
                }
            });
            fail("Expected call to fail");
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);

            assertTrue(sw.toString(), sw.toString().contains("Rejected: "+Security218.class.getName()));
            assertTrue(ATTACKS.toString(), ATTACKS.isEmpty());
            assertFalse(ATTACKS.contains("napoleon>north"));
        }
    }

    /**
     * Control case for {@link #successful_defense()} that proves that we are testing the right thing.
     */
    @Test
    public void successful_attack() throws Exception {
        final Security218 a = new Security218("caesar");
        north.call(new CallableBase<Void, IOException>() {
            @Override
            public Void call() throws IOException {
                a.toString();   // this will ensure 'a' gets sent over
                return null;
            }
        });
        assertTrue(ATTACKS.contains("caesar>south"));
    }

    /**
     * An attack payload that leaves a trace on the receiver side if it gets read from the stream.
     */
    static class Security218 implements Serializable {
        private final String attack;

        public Security218(String attack) {
            this.attack = attack;
        }

        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
            ois.defaultReadObject();
            ATTACKS.add(attack+">"+Channel.current().getName());
        }
    }

    /**
     * Successful attacks will leave a trace here.<commit_msg>Clarifying my thoughts on what needs to be tested<commit_after>package hudson.remoting;

import hudson.remoting.Channel.Mode;
import hudson.remoting.CommandTransport.CommandReceiver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.*;

/**
 * Tests the effect of {@link ClassFilter}.
 *
 * <p>
 * This test code targets each of the known layers where object serialization is used.
 * Specifically, those are {@link ObjectInputStream} (and subtypes) created in:
 *
 * <ul>
 * <li>{@link Capability#read(InputStream)}
 * <li>{@link UserRequest#deserialize(Channel, byte[], ClassLoader)},
 * <li>{@link ChannelBuilder#makeTransport(InputStream, OutputStream, Mode, Capability)}
 * <li>{@link AbstractByteArrayCommandTransport#setup(Channel, CommandReceiver)}
 * <li>{@link AbstractSynchronousByteArrayCommandTransport#read()}
 * </ul>
 *
 * @author <NAME>
 */
public class ClassFilterTest implements Serializable {

    /**
     * North can defend itself from south but not the other way around.
     */
    private transient InProcessRunner runner = new InProcessRunner() {
        @Override
        protected ChannelBuilder configureNorth() {
            return super.configureNorth()
                    .withClassFilter(new TestFilter());
        }
    };

    private transient Channel north, south;

    private static class TestFilter extends ClassFilter {
        @Override
        protected boolean isBlacklisted(String name) {
            if (name.contains("Security218"))
                return true;
            return false;
        }
    }

    /**
     * Set up a channel pair where french side is well protected by british side is not.
     */
    @Before
    public void setUp() throws Exception {
        north = runner.start();
        south = runner.south;
        ATTACKS.clear();
    }

    @After
    public void tearDown() throws Exception {
        runner.stop(north);
    }

    @Test
    public void userRequest() throws Exception {
        try {
            final Security218 a = new Security218("napoleon");
            south.call(new CallableBase<Void, IOException>() {
                @Override
                public Void call() throws IOException {
                    a.toString();   // this will ensure 'a' gets sent over
                    return null;
                }
            });
            fail("Expected call to fail");
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);

            assertTrue(sw.toString(), sw.toString().contains("Rejected: "+Security218.class.getName()));
            assertTrue(ATTACKS.toString(), ATTACKS.isEmpty());
            assertFalse(ATTACKS.contains("napoleon>north"));
        }
    }

    /**
     * Control case for {@link #userRequest()} that proves that we are testing the right thing.
     */
    @Test
    public void userRequest_control() throws Exception {
        final Security218 a = new Security218("caesar");
        north.call(new CallableBase<Void, IOException>() {
            @Override
            public Void call() throws IOException {
                a.toString();   // this will ensure 'a' gets sent over
                return null;
            }
        });
        assertTrue(ATTACKS.contains("caesar>south"));
    }

    /**
     * An attack payload that leaves a trace on the receiver side if it gets read from the stream.
     */
    static class Security218 implements Serializable {
        private final String attack;

        public Security218(String attack) {
            this.attack = attack;
        }

        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
            ois.defaultReadObject();
            ATTACKS.add(attack+">"+Channel.current().getName());
        }
    }

    /**
     * Successful attacks will leave a trace here.
{'fraction_non_alphanumeric': 0.09885237350026083, 'fraction_numerical': 0.006259780907668232, 'mean_word_length': 2.285775492716367, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1882754', 'n_tokens_mistral': 1999, 'n_tokens_neox': 1900, 'n_words': 583}