Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
commit
6793e7e985
|
@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
|
||||||
class AsyncContentProducer implements ContentProducer
|
class AsyncContentProducer implements ContentProducer
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(AsyncContentProducer.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AsyncContentProducer.class);
|
||||||
|
private static final HttpInput.ErrorContent RECYCLED_ERROR_CONTENT = new HttpInput.ErrorContent(new IllegalStateException("ContentProducer has been recycled"));
|
||||||
private static final Throwable UNCONSUMED_CONTENT_EXCEPTION = new IOException("Unconsumed content")
|
private static final Throwable UNCONSUMED_CONTENT_EXCEPTION = new IOException("Unconsumed content")
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,9 +67,30 @@ class AsyncContentProducer implements ContentProducer
|
||||||
assertLocked();
|
assertLocked();
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("recycling {}", this);
|
LOG.debug("recycling {}", this);
|
||||||
|
|
||||||
|
// Make sure that the content has been fully consumed before destroying the interceptor and also make sure
|
||||||
|
// that asking this instance for content between recycle and reopen will only produce error'ed content.
|
||||||
|
if (_rawContent == null)
|
||||||
|
_rawContent = RECYCLED_ERROR_CONTENT;
|
||||||
|
else if (!_rawContent.isSpecial())
|
||||||
|
throw new IllegalStateException("ContentProducer with unconsumed content cannot be recycled");
|
||||||
|
|
||||||
|
if (_transformedContent == null)
|
||||||
|
_transformedContent = RECYCLED_ERROR_CONTENT;
|
||||||
|
else if (!_transformedContent.isSpecial())
|
||||||
|
throw new IllegalStateException("ContentProducer with unconsumed content cannot be recycled");
|
||||||
|
|
||||||
if (_interceptor instanceof Destroyable)
|
if (_interceptor instanceof Destroyable)
|
||||||
((Destroyable)_interceptor).destroy();
|
((Destroyable)_interceptor).destroy();
|
||||||
_interceptor = null;
|
_interceptor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reopen()
|
||||||
|
{
|
||||||
|
assertLocked();
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("reopening {}", this);
|
||||||
_rawContent = null;
|
_rawContent = null;
|
||||||
_transformedContent = null;
|
_transformedContent = null;
|
||||||
_error = false;
|
_error = false;
|
||||||
|
|
|
@ -46,6 +46,14 @@ class BlockingContentProducer implements ContentProducer
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("recycling {}", this);
|
LOG.debug("recycling {}", this);
|
||||||
_asyncContentProducer.recycle();
|
_asyncContentProducer.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reopen()
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("reopening {}", this);
|
||||||
|
_asyncContentProducer.reopen();
|
||||||
_semaphore.drainPermits();
|
_semaphore.drainPermits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.component.Destroyable;
|
||||||
import org.eclipse.jetty.util.thread.AutoLock;
|
import org.eclipse.jetty.util.thread.AutoLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,17 +28,24 @@ import org.eclipse.jetty.util.thread.AutoLock;
|
||||||
public interface ContentProducer
|
public interface ContentProducer
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Lock this instance. The lock must be held before any method of this instance's
|
* Lock this instance. The lock must be held before any of this instance's
|
||||||
* method be called, and must be manually released afterward.
|
* method can be called, and must be released afterward.
|
||||||
* @return the lock that is guarding this instance.
|
* @return the lock that is guarding this instance.
|
||||||
*/
|
*/
|
||||||
AutoLock lock();
|
AutoLock lock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset all internal state and clear any held resources.
|
* Clear the interceptor and call {@link Destroyable#destroy()} on it if it implements {@link Destroyable}.
|
||||||
|
* A recycled {@link ContentProducer} will only produce special content with a non-null error until
|
||||||
|
* {@link #reopen()} is called.
|
||||||
*/
|
*/
|
||||||
void recycle();
|
void recycle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset all internal state, making this is instance logically equivalent to a freshly allocated one.
|
||||||
|
*/
|
||||||
|
void reopen();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fail all content currently available in this {@link ContentProducer} instance
|
* Fail all content currently available in this {@link ContentProducer} instance
|
||||||
* as well as in the underlying {@link HttpChannel}.
|
* as well as in the underlying {@link HttpChannel}.
|
||||||
|
|
|
@ -55,8 +55,12 @@ public class HttpInput extends ServletInputStream implements Runnable
|
||||||
|
|
||||||
public void recycle()
|
public void recycle()
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
try (AutoLock lock = _contentProducer.lock())
|
||||||
LOG.debug("recycle {}", this);
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("recycle {}", this);
|
||||||
|
_blockingContentProducer.recycle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reopen()
|
public void reopen()
|
||||||
|
@ -65,7 +69,7 @@ public class HttpInput extends ServletInputStream implements Runnable
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("reopen {}", this);
|
LOG.debug("reopen {}", this);
|
||||||
_blockingContentProducer.recycle();
|
_blockingContentProducer.reopen();
|
||||||
_contentProducer = _blockingContentProducer;
|
_contentProducer = _blockingContentProducer;
|
||||||
_consumedEof = false;
|
_consumedEof = false;
|
||||||
_readListener = null;
|
_readListener = null;
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast String Utilities.
|
* Fast String Utilities.
|
||||||
|
@ -774,6 +775,47 @@ public class StringUtil
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] fromHexString(String s)
|
||||||
|
{
|
||||||
|
if (s.length() % 2 != 0)
|
||||||
|
throw new IllegalArgumentException(s);
|
||||||
|
byte[] array = new byte[s.length() / 2];
|
||||||
|
for (int i = 0; i < array.length; i++)
|
||||||
|
{
|
||||||
|
int b = Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
|
||||||
|
array[i] = (byte)(0xff & b);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toHexString(byte b)
|
||||||
|
{
|
||||||
|
return toHexString(new byte[]{b}, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toHexString(byte[] b)
|
||||||
|
{
|
||||||
|
return toHexString(Objects.requireNonNull(b, "ByteBuffer cannot be null"), 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toHexString(byte[] b, int offset, int length)
|
||||||
|
{
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (int i = offset; i < offset + length; i++)
|
||||||
|
{
|
||||||
|
int bi = 0xff & b[i];
|
||||||
|
int c = '0' + (bi / 16) % 16;
|
||||||
|
if (c > '9')
|
||||||
|
c = 'A' + (c - '0' - 10);
|
||||||
|
buf.append((char)c);
|
||||||
|
c = '0' + bi % 16;
|
||||||
|
if (c > '9')
|
||||||
|
c = 'a' + (c - '0' - 10);
|
||||||
|
buf.append((char)c);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static String printable(String name)
|
public static String printable(String name)
|
||||||
{
|
{
|
||||||
if (name == null)
|
if (name == null)
|
||||||
|
|
|
@ -400,6 +400,10 @@ public class TypeUtil
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link StringUtil#fromHexString(String)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static byte[] parseBytes(String s, int base)
|
public static byte[] parseBytes(String s, int base)
|
||||||
{
|
{
|
||||||
byte[] bytes = new byte[s.length() / 2];
|
byte[] bytes = new byte[s.length() / 2];
|
||||||
|
@ -507,45 +511,40 @@ public class TypeUtil
|
||||||
toHex((int)value, buf);
|
toHex((int)value, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link StringUtil#toHexString(byte)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static String toHexString(byte b)
|
public static String toHexString(byte b)
|
||||||
{
|
{
|
||||||
return toHexString(new byte[]{b}, 0, 1);
|
return StringUtil.toHexString(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link StringUtil#toHexString(byte[])} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static String toHexString(byte[] b)
|
public static String toHexString(byte[] b)
|
||||||
{
|
{
|
||||||
return toHexString(b, 0, b.length);
|
return StringUtil.toHexString(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link StringUtil#toHexString(byte[], int, int)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static String toHexString(byte[] b, int offset, int length)
|
public static String toHexString(byte[] b, int offset, int length)
|
||||||
{
|
{
|
||||||
StringBuilder buf = new StringBuilder();
|
return StringUtil.toHexString(b, offset, length);
|
||||||
for (int i = offset; i < offset + length; i++)
|
|
||||||
{
|
|
||||||
int bi = 0xff & b[i];
|
|
||||||
int c = '0' + (bi / 16) % 16;
|
|
||||||
if (c > '9')
|
|
||||||
c = 'A' + (c - '0' - 10);
|
|
||||||
buf.append((char)c);
|
|
||||||
c = '0' + bi % 16;
|
|
||||||
if (c > '9')
|
|
||||||
c = 'a' + (c - '0' - 10);
|
|
||||||
buf.append((char)c);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link StringUtil#fromHexString(String)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static byte[] fromHexString(String s)
|
public static byte[] fromHexString(String s)
|
||||||
{
|
{
|
||||||
if (s.length() % 2 != 0)
|
return StringUtil.fromHexString(s);
|
||||||
throw new IllegalArgumentException(s);
|
|
||||||
byte[] array = new byte[s.length() / 2];
|
|
||||||
for (int i = 0; i < array.length; i++)
|
|
||||||
{
|
|
||||||
int b = Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
|
|
||||||
array[i] = (byte)(0xff & b);
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dump(Class<?> c)
|
public static void dump(Class<?> c)
|
||||||
|
|
|
@ -19,12 +19,9 @@ import java.security.MessageDigest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.thread.AutoLock;
|
import org.eclipse.jetty.util.thread.AutoLock;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credentials. The Credential class represents an abstract mechanism for checking authentication credentials. A credential instance either represents a secret,
|
* Credentials. The Credential class represents an abstract mechanism for checking authentication credentials. A credential instance either represents a secret,
|
||||||
|
@ -39,10 +36,12 @@ import org.slf4j.LoggerFactory;
|
||||||
*/
|
*/
|
||||||
public abstract class Credential implements Serializable
|
public abstract class Credential implements Serializable
|
||||||
{
|
{
|
||||||
|
// NOTE: DO NOT INTRODUCE LOGGING TO THIS CLASS
|
||||||
private static final long serialVersionUID = -7760551052768181572L;
|
private static final long serialVersionUID = -7760551052768181572L;
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Credential.class);
|
// Intentionally NOT using TypeUtil.serviceProviderStream
|
||||||
private static final List<CredentialProvider> CREDENTIAL_PROVIDERS = TypeUtil.serviceProviderStream(ServiceLoader.load(CredentialProvider.class))
|
// as that introduces a Logger requirement that command line Password cannot use.
|
||||||
.flatMap(p -> Stream.of(p.get()))
|
private static final List<CredentialProvider> CREDENTIAL_PROVIDERS = ServiceLoader.load(CredentialProvider.class).stream()
|
||||||
|
.map(ServiceLoader.Provider::get)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,8 +153,7 @@ public abstract class Credential implements Serializable
|
||||||
{
|
{
|
||||||
if (credentials instanceof char[])
|
if (credentials instanceof char[])
|
||||||
credentials = new String((char[])credentials);
|
credentials = new String((char[])credentials);
|
||||||
if (!(credentials instanceof String) && !(credentials instanceof Password))
|
|
||||||
LOG.warn("Can't check {} against CRYPT", credentials.getClass());
|
|
||||||
return stringEquals(_cooked, UnixCrypt.crypt(credentials.toString(), _cooked));
|
return stringEquals(_cooked, UnixCrypt.crypt(credentials.toString(), _cooked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +187,7 @@ public abstract class Credential implements Serializable
|
||||||
MD5(String digest)
|
MD5(String digest)
|
||||||
{
|
{
|
||||||
digest = digest.startsWith(__TYPE) ? digest.substring(__TYPE.length()) : digest;
|
digest = digest.startsWith(__TYPE) ? digest.substring(__TYPE.length()) : digest;
|
||||||
_digest = TypeUtil.parseBytes(digest, 16);
|
_digest = StringUtil.fromHexString(digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getDigest()
|
public byte[] getDigest()
|
||||||
|
@ -229,13 +227,12 @@ public abstract class Credential implements Serializable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG.warn("Can't check {} against MD5", credentials.getClass());
|
// Not a MD5 or Credential class
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Failed message digest", e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +245,9 @@ public abstract class Credential implements Serializable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only by Command Line Password utility
|
||||||
|
*/
|
||||||
public static String digest(String password)
|
public static String digest(String password)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -263,7 +263,8 @@ public abstract class Credential implements Serializable
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Unable to access MD5 message digest", e);
|
System.err.println("Unable to access MD5 message digest");
|
||||||
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,11 +274,12 @@ public abstract class Credential implements Serializable
|
||||||
digest = __md.digest();
|
digest = __md.digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
return __TYPE + TypeUtil.toString(digest, 16);
|
return __TYPE + StringUtil.toHexString(digest);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Message Digest failure", e);
|
System.err.println("Message Digest Failure");
|
||||||
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,6 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password utility class.
|
* Password utility class.
|
||||||
*
|
*
|
||||||
|
@ -47,8 +44,7 @@ import org.slf4j.LoggerFactory;
|
||||||
*/
|
*/
|
||||||
public class Password extends Credential
|
public class Password extends Credential
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Password.class);
|
// NOTE: DO NOT INTRODUCE LOGGING TO THIS CLASS
|
||||||
|
|
||||||
private static final long serialVersionUID = 5062906681431569445L;
|
private static final long serialVersionUID = 5062906681431569445L;
|
||||||
|
|
||||||
public static final String __OBFUSCATE = "OBF:";
|
public static final String __OBFUSCATE = "OBF:";
|
||||||
|
@ -224,7 +220,9 @@ public class Password extends Credential
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOG.warn("EXCEPTION", e);
|
// only seen with command line input style
|
||||||
|
System.err.println("ERROR: Bad/Invalid password.");
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
if (passwd == null || passwd.length() == 0)
|
if (passwd == null || passwd.length() == 0)
|
||||||
passwd = promptDft;
|
passwd = promptDft;
|
||||||
|
@ -247,5 +245,6 @@ public class Password extends Credential
|
||||||
System.err.println(Credential.MD5.digest(p));
|
System.err.println(Credential.MD5.digest(p));
|
||||||
if (arg.length == 2)
|
if (arg.length == 2)
|
||||||
System.err.println(Credential.Crypt.crypt(arg[0], pw.toString()));
|
System.err.println(Credential.Crypt.crypt(arg[0], pw.toString()));
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,10 @@ import static org.hamcrest.Matchers.arrayContaining;
|
||||||
import static org.hamcrest.Matchers.emptyArray;
|
import static org.hamcrest.Matchers.emptyArray;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
|
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
|
||||||
|
@ -266,4 +268,34 @@ public class StringUtilTest
|
||||||
|
|
||||||
assertThat(StringUtil.csvSplit("\"aaa\", \" b,\\\"\",\"\""), arrayContaining("aaa", " b,\"", ""));
|
assertThat(StringUtil.csvSplit("\"aaa\", \" b,\\\"\",\"\""), arrayContaining("aaa", " b,\"", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromHexStringGood()
|
||||||
|
{
|
||||||
|
assertArrayEquals(new byte[]{0x12, 0x34, 0x56, 0x78, (byte)0x9A}, StringUtil.fromHexString("123456789A"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromHexStringBad()
|
||||||
|
{
|
||||||
|
assertThrows(NumberFormatException.class, () -> StringUtil.fromHexString("Hello World "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToHexStringGood()
|
||||||
|
{
|
||||||
|
assertThat(StringUtil.toHexString(new byte[]{0x12, 0x34, 0x56, 0x78, (byte)0x9A}), is("123456789a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToHexStringNull()
|
||||||
|
{
|
||||||
|
assertThrows(NullPointerException.class, () -> StringUtil.toHexString(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToHexStringEmpty()
|
||||||
|
{
|
||||||
|
assertThat(StringUtil.toHexString(new byte[0]), is(""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ package org.eclipse.jetty.util.security;
|
||||||
import org.eclipse.jetty.util.security.Credential.Crypt;
|
import org.eclipse.jetty.util.security.Credential.Crypt;
|
||||||
import org.eclipse.jetty.util.security.Credential.MD5;
|
import org.eclipse.jetty.util.security.Credential.MD5;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -99,4 +101,17 @@ public class CredentialTest
|
||||||
assertFalse(Credential.byteEquals("".getBytes(), "fooo".getBytes()));
|
assertFalse(Credential.byteEquals("".getBytes(), "fooo".getBytes()));
|
||||||
assertTrue(Credential.byteEquals("".getBytes(), "".getBytes()));
|
assertTrue(Credential.byteEquals("".getBytes(), "".getBytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"OBF:1v2j1uum1xtv1zej1zer1xtn1uvk1v1v",
|
||||||
|
"MD5:5f4dcc3b5aa765d61d8327deb882cf99",
|
||||||
|
"CRYPT:usjRS48E8ZADM"
|
||||||
|
})
|
||||||
|
public void testGetCredential(String encoded)
|
||||||
|
{
|
||||||
|
Credential credential = Credential.getCredential(encoded);
|
||||||
|
assertTrue(credential.check(Credential.getCredential("password")));
|
||||||
|
assertTrue(credential.check("password"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,22 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.util.security;
|
package org.eclipse.jetty.util.security;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
public class PasswordTest
|
public class PasswordTest
|
||||||
{
|
{
|
||||||
|
@ -44,4 +57,40 @@ public class PasswordTest
|
||||||
String obfuscate = Password.obfuscate(password);
|
String obfuscate = Password.obfuscate(password);
|
||||||
assertEquals(password, Password.deobfuscate(obfuscate));
|
assertEquals(password, Password.deobfuscate(obfuscate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCommandLineUsage() throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
ProcessBuilder passwordBuilder = new ProcessBuilder()
|
||||||
|
.directory(MavenTestingUtils.getTargetDir())
|
||||||
|
.command("java",
|
||||||
|
"-cp", MavenTestingUtils.getTargetPath("classes").toString(),
|
||||||
|
Password.class.getName(),
|
||||||
|
"user", "password")
|
||||||
|
.redirectErrorStream(true);
|
||||||
|
|
||||||
|
Process passwordProcess = passwordBuilder.start();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(passwordProcess.getInputStream())))
|
||||||
|
{
|
||||||
|
String output = reader.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||||
|
if (passwordProcess.waitFor(5, TimeUnit.SECONDS))
|
||||||
|
{
|
||||||
|
int exitCode = passwordProcess.exitValue();
|
||||||
|
assertThat("Non-error exit code: " + output, exitCode, is(0));
|
||||||
|
assertThat("Output", output, not(containsString("Exception")));
|
||||||
|
assertThat("Output", output, allOf(
|
||||||
|
containsString("password"),
|
||||||
|
containsString("OBF:"),
|
||||||
|
containsString("MD5:"),
|
||||||
|
containsString("CRYPT:")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.out.println(output);
|
||||||
|
passwordProcess.destroy();
|
||||||
|
fail("Process didn't exit properly (was forcibly destroyed)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -40,13 +40,13 @@
|
||||||
<felix.version>7.0.3</felix.version>
|
<felix.version>7.0.3</felix.version>
|
||||||
<findbugs.jsr305.version>3.0.2</findbugs.jsr305.version>
|
<findbugs.jsr305.version>3.0.2</findbugs.jsr305.version>
|
||||||
<google.errorprone.version>2.10.0</google.errorprone.version>
|
<google.errorprone.version>2.10.0</google.errorprone.version>
|
||||||
<grpc.version>1.42.1</grpc.version>
|
<grpc.version>1.43.0</grpc.version>
|
||||||
<gson.version>2.8.9</gson.version>
|
<gson.version>2.8.9</gson.version>
|
||||||
<guava.version>31.0.1-jre</guava.version>
|
<guava.version>31.0.1-jre</guava.version>
|
||||||
<guice.version>5.0.1</guice.version>
|
<guice.version>5.0.1</guice.version>
|
||||||
<hamcrest.version>2.2</hamcrest.version>
|
<hamcrest.version>2.2</hamcrest.version>
|
||||||
<hawtio.version>2.14.2</hawtio.version>
|
<hawtio.version>2.14.2</hawtio.version>
|
||||||
<hazelcast.version>4.2.2</hazelcast.version>
|
<hazelcast.version>4.2.3</hazelcast.version>
|
||||||
<infinispan.version>11.0.11.Final</infinispan.version>
|
<infinispan.version>11.0.11.Final</infinispan.version>
|
||||||
<infinispan.protostream.version>4.3.4.Final</infinispan.protostream.version>
|
<infinispan.protostream.version>4.3.4.Final</infinispan.protostream.version>
|
||||||
<jackson-databind.version>2.13.0</jackson-databind.version>
|
<jackson-databind.version>2.13.0</jackson-databind.version>
|
||||||
|
|
Loading…
Reference in New Issue