blob: 9f45a32789baf4f890d97ae9d6ff6f2c997e7e83 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.qpid.server.user.connection.limits.config;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Collections;
import com.google.common.collect.Iterables;
import org.junit.Test;
import org.mockito.Mockito;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.test.utils.UnitTestBase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class FileParserTest extends UnitTestBase
{
private static final String FILE_SUFFIX = "clt";
private static final Charset CHARSET = StandardCharsets.UTF_8;
@Test
public void testParseRule_ConnectionCountLimit()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection_limit=10");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertNotNull(rule.getFrequencyLimits());
assertNull(rule.getFrequencyPeriod());
assertNull(rule.getFrequencyLimit());
assertTrue(rule.getFrequencyLimits().isEmpty());
}
@Test
public void testParseRule_ConnectionFrequencyLimit()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection-frequency-limit=10/15M");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Collections.singletonMap(Duration.ofMinutes(15L), 10), rule.getFrequencyLimits());
assertEquals(Duration.ofMinutes(15L), rule.getFrequencyPeriod());
assertEquals(Integer.valueOf(10), rule.getFrequencyLimit());
assertNull(rule.getCountLimit());
}
@Test
public void testParseRule_ConnectionFrequencyLimit_1minute()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection-frequency-limit=17/m");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Collections.singletonMap(Duration.ofMinutes(1L), 17), rule.getFrequencyLimits());
assertEquals(Duration.ofMinutes(1L), rule.getFrequencyPeriod());
assertEquals(Integer.valueOf(17), rule.getFrequencyLimit());
assertNull(rule.getCountLimit());
}
@Test
public void testParseRule_ConnectionFrequencyLimit_genericPeriod()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection-frequency-limit=17/P1dT1m17.7s");
final Duration duration = Duration.parse("P1dT1m17.7s");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Collections.singletonMap(duration, 17), rule.getFrequencyLimits());
assertEquals(duration, rule.getFrequencyPeriod());
assertEquals(Integer.valueOf(17), rule.getFrequencyLimit());
assertNull(rule.getCountLimit());
}
@Test
public void testParseRule_ConnectionFrequencyLimit_noPeriod()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection-frequency-limit=17");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertNull(rule.getFrequencyPeriod());
assertEquals(Integer.valueOf(17), rule.getFrequencyLimit());
assertNull(rule.getCountLimit());
}
@Test
public void testParseRule_ConnectionLimit()
{
final RuleSetCreator creator = writeConfig("CLT user port=amqp connection_limit=10 connection-frequency-limit=20/m");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertEquals(Integer.valueOf(20), rule.getFrequencyLimit());
assertEquals(Duration.ofMinutes(1L), rule.getFrequencyPeriod());
assertEquals(Collections.singletonMap(Duration.ofMinutes(1L), 20), rule.getFrequencyLimits());
}
@Test
public void testParseRule_ConnectionLimit2()
{
final RuleSetCreator creator = writeConfig("CLT\tuser\tport='amqp' connection_limit=\"10\" connection-frequency-limit='20/h'");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertEquals(Integer.valueOf(20), rule.getFrequencyLimit());
assertEquals(Duration.ofHours(1L), rule.getFrequencyPeriod());
assertEquals(Collections.singletonMap(Duration.ofHours(1L), 20), rule.getFrequencyLimits());
}
@Test
public void testParseRule_Continuation()
{
final RuleSetCreator creator = writeConfig("CLT user \\ \n connectionLimit=10 connection-frequency-limit=20");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertEquals(Integer.valueOf(20), rule.getFrequencyLimit());
}
@Test
public void testParseRule_Blocked()
{
final RuleSetCreator creator = writeConfig("CLT user block port=amqp");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals("amqp", rule.getPort());
assertTrue(rule.isUserBlocked());
assertEquals(Integer.valueOf(0), rule.getCountLimit());
assertEquals(Integer.valueOf(0), rule.getFrequencyLimit());
assertNotNull(rule.getFrequencyLimits());
assertTrue(rule.getFrequencyLimits().isEmpty());
}
@Test
public void testParseRule_DefaultPort()
{
final RuleSetCreator creator = writeConfig("CLT user connection_limit=10 connection-frequency-limit=20");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertEquals(Integer.valueOf(20), rule.getFrequencyLimit());
}
@Test
public void testParseRule_Empty()
{
final RuleSetCreator creator = writeConfig("CLT user port=all");
assertTrue(creator.isEmpty());
}
@Test
public void testParseConfig()
{
final RuleSetCreator creator = writeConfig("CONFIG log-all=true default-frequency-period=200000");
assertTrue(creator.isEmpty());
assertTrue(creator.isLogAllMessages());
assertEquals(Long.valueOf(200000L), creator.getDefaultFrequencyPeriod());
}
@Test
public void testParseConfig_alternative()
{
final RuleSetCreator creator = writeConfig("CONFIG logAll=true defaultFrequencyPeriod=200000");
assertTrue(creator.isEmpty());
assertTrue(creator.isLogAllMessages());
assertEquals(Long.valueOf(200000L), creator.getDefaultFrequencyPeriod());
}
@Test
public void testParseConfig_Empty()
{
final RuleSetCreator creator = writeConfig("CONFIG log-all=false");
assertTrue(creator.isEmpty());
assertFalse(creator.isLogAllMessages());
assertNull(creator.getDefaultFrequencyPeriod());
}
@Test
public void testParseAclRule_ConnectionCountLimit()
{
final RuleSetCreator creator = writeConfig("ACL ALLOW-LOG user ACCESS VIRTUALHOST connection_limit=10");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
assertNull(rule.getFrequencyLimit());
assertNotNull(rule.getFrequencyLimits());
assertTrue(rule.getFrequencyLimits().isEmpty());
}
@Test
public void testParseAclRule_ConnectionFrequencyLimit()
{
final RuleSetCreator creator = writeConfig("ACL ALLOW-LOG user ACCESS VIRTUALHOST connection_frequency_limit=60");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(60), rule.getFrequencyLimit());
assertNull(rule.getCountLimit());
}
@Test
public void testParseAclRule_ConnectionLimit()
{
final RuleSetCreator creator = writeConfig("ACL ALLOW-LOG user ACCESS VIRTUALHOST connection_limit=10 connection_frequency_limit=60");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(60), rule.getFrequencyLimit());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
}
@Test
public void testParseAclRule_ConnectionLimit2()
{
final RuleSetCreator creator = writeConfig("27 ACL ALLOW-LOG user ACCESS VIRTUALHOST connection_limit=10 connection_frequency_limit=60");
final Rule rule = Iterables.getFirst(creator, null);
assertNotNull(rule);
assertEquals("user", rule.getIdentity());
assertEquals(RulePredicates.ALL_PORTS, rule.getPort());
assertFalse(rule.isUserBlocked());
assertEquals(Integer.valueOf(60), rule.getFrequencyLimit());
assertEquals(Integer.valueOf(10), rule.getCountLimit());
}
@Test
public void testParseAclRule_Empty()
{
final RuleSetCreator creator = writeConfig("ACL ALLOW-LOG user ACCESS VIRTUALHOST name=vhost");
assertTrue(creator.isEmpty());
}
@Test
public void testParseAclRule_Empty2()
{
final RuleSetCreator creator = writeConfig("ACL DENY user ACCESS");
assertTrue(creator.isEmpty());
}
@Test
public void testParse_Error_Continuation()
{
try
{
writeConfig("CLT user \\ connection_limit=10 connection_frequency_limit=60");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.PREMATURE_CONTINUATION, 1), e.getMessage());
}
}
@Test
public void testParse_Error_NotEnoughTokens()
{
try
{
writeConfig("CLT");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.NOT_ENOUGH_TOKENS, 1), e.getMessage());
}
}
@Test
public void testParse_Error_UnknownTokens()
{
try
{
writeConfig("CLT user connection_limit=10 connection_frequency_limit=60 name=vhost");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.UNKNOWN_CLT_PROPERTY_MSG, "name", 1), e.getMessage());
}
}
@Test
public void testParse_Error_OrderNumber()
{
try
{
writeConfig("7 CLT user connection_limit=10 connection_frequency_limit=60");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.NUMBER_NOT_ALLOWED, "CLT", 1), e.getMessage());
}
}
@Test
public void testParse_Error_NumberFormat()
{
try
{
writeConfig("CLT user connection_limit=10 connection_frequency_limit=xc");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.PARSE_TOKEN_FAILED, 1), e.getMessage());
}
}
@Test
public void testParse_Error_MissingEqualSign()
{
try
{
writeConfig("CLT user connection_limit=10 connection_frequency_limit,60");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.PROPERTY_NO_EQUALS_MSG, 1), e.getMessage());
}
}
@Test
public void testParse_Error_MissingValue()
{
try
{
writeConfig("CLT user connection_limit=10 connection_frequency_limit=");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.PROPERTY_NO_VALUE_MSG, 1), e.getMessage());
}
}
@Test
public void testParse_Error_KeyOnly()
{
try
{
writeConfig("CLT user connection_limit=10 connection_frequency_limit");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.PROPERTY_KEY_ONLY_MSG, 1), e.getMessage());
}
}
@Test
public void testParse_Error_UnknownToken()
{
try
{
writeConfig("GROUP group user");
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertEquals(String.format(FileParser.UNRECOGNISED_INITIAL_TOKEN, "GROUP", 1), e.getMessage());
}
}
@Test
public void testParse_Error_UnknownFile()
{
final String prefix = getClass().getSimpleName() + "." + getTestName();
final Path connecionLimitFile;
try
{
connecionLimitFile = Files.createTempFile(prefix, FILE_SUFFIX);
Files.deleteIfExists(connecionLimitFile);
}
catch (IOException e)
{
throw new IllegalStateException("Failed to create a file: " + prefix + FILE_SUFFIX);
}
try
{
FileParser.parse(connecionLimitFile.toAbsolutePath().toString());
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertNotNull(e.getMessage());
}
}
@Test
public void testParse_IOException() throws IOException
{
Reader reader = Mockito.mock(Reader.class);
Mockito.doThrow(new IOException("exception")).when(reader).reset();
Mockito.doThrow(new IOException("exception")).when(reader).ready();
Mockito.doThrow(new IOException("exception")).when(reader).close();
Mockito.doThrow(new IOException("exception")).when(reader).read(Mockito.any(CharBuffer.class));
Mockito.doThrow(new IOException("exception")).when(reader).read(Mockito.any(char[].class));
Mockito.doThrow(new IOException("exception")).when(reader).read(Mockito.any(char[].class), Mockito.anyInt(), Mockito.anyInt());
Mockito.doThrow(new IOException("exception")).when(reader).mark(Mockito.anyInt());
Mockito.doThrow(new IOException("exception")).when(reader).skip(Mockito.anyLong());
try
{
new FileParser().readAndParse(reader);
fail("An exception is expected");
}
catch (IllegalConfigurationException e)
{
assertNotNull(e.getMessage());
}
}
private RuleSetCreator writeConfig(String... data)
{
final String prefix = getClass().getSimpleName() + "." + getTestName();
final Path connectionLimitFile;
try
{
connectionLimitFile = Files.createTempFile(prefix, FILE_SUFFIX);
Files.deleteIfExists(connectionLimitFile);
}
catch (IOException e)
{
throw new IllegalStateException("Failed to create a file: " + prefix + FILE_SUFFIX);
}
try (BufferedWriter writer = Files.newBufferedWriter(connectionLimitFile, CHARSET))
{
for (String line : data)
{
writer.write(line);
writer.newLine();
writer.flush();
}
}
catch (IOException x)
{
throw new IllegalStateException("Failed to write into the file " + connectionLimitFile.getFileName());
}
return FileParser.parse(connectionLimitFile.toAbsolutePath().toString());
}
}