Handle malformed license signatures (#37137)

This commit adds a more user friendly error message when a license
signature is malformed/truncated in a way that it cannot be
meaningfully parsed.
This commit is contained in:
Ioannis Kakavas 2019-01-09 07:29:22 +02:00 committed by GitHub
parent 2a79c468f8
commit 9049263c2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 129 additions and 3 deletions

View File

@ -469,9 +469,17 @@ public class License implements ToXContentObject {
}
// not a license spec
if (builder.signature != null) {
byte[] signatureBytes = Base64.getDecoder().decode(builder.signature);
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
int version = byteBuffer.getInt();
int version;
// In case the signature is truncated/malformed we might end up with fewer than 4 bytes in the byteBuffer
// or with a string that cannot be base64 decoded. In either case return a more friendly error instead of
// just throwing the BufferUnderflowException or the IllegalArgumentException
try {
byte[] signatureBytes = Base64.getDecoder().decode(builder.signature);
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
version = byteBuffer.getInt();
} catch (Exception e) {
throw new ElasticsearchException("malformed signature for license [" + builder.uid + "]", e);
}
// we take the absolute version, because negative versions
// mean that the license was generated by the cluster (see TrialLicense)
// and positive version means that the license was signed

View File

@ -0,0 +1,118 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import java.nio.BufferUnderflowException;
import java.nio.charset.StandardCharsets;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
public class LicenseTests extends ESTestCase {
public void testFromXContent() throws Exception {
String licenseString = "{\"license\":" +
"{\"uid\":\"4056779d-b823-4c12-a9cb-efa4a8d8c422\"," +
"\"type\":\"gold\"," +
"\"issue_date_in_millis\":1546589020459," +
"\"expiry_date_in_millis\":1546596340459," +
"\"max_nodes\":5," +
"\"issued_to\":\"customer\"," +
"\"issuer\":\"elasticsearch\"," +
"\"signature\":\"AAAAAgAAAA34V2kfTJVtvdL2LttwAAABmFJ6NGRnbEM3WVQrZVQwNkdKQmR1VytlMTMyM1J0dTZ1WGwyY2ZCVFhqMGtJU2gzZ3pnNTVpOW" +
"F5Y1NaUkwyN2VsTEtCYnlZR2c5WWtjQ0phaDlhRjlDUXViUmUwMWhjSkE2TFcwSGdneTJHbUV4N2RHUWJxV20ybjRsZHRzV2xkN0ZmdDlYblJmNVcxMlBWeU81" +
"V1hLUm1EK0V1dmF3cFdlSGZzTU5SZE1qUmFra3JkS1hCanBWVmVTaFFwV3BVZERzeG9Sci9rYnlJK2toODZXY09tNmFHUVNUL3IyUHExV3VSTlBneWNJcFQ0bX" +
"l0cmhNNnRwbE1CWE4zWjJ5eGFuWFo0NGhsb3B5WFd1eTdYbFFWQkxFVFFPSlBERlB0eVVJYXVSZ0lsR2JpRS9rN1h4MSsvNUpOcGN6cU1NOHN1cHNtSTFIUGN1" +
"bWNGNEcxekhrblhNOXZ2VEQvYmRzQUFwbytUZEpRR3l6QU5oS2ZFSFdSbGxxNDZyZ0xvUHIwRjdBL2JqcnJnNGFlK09Cek9pYlJ5Umc9PQAAAQAth77fQLF7CC" +
"EL7wA6Z0/UuRm/weECcsjW/50kBnPLO8yEs+9/bPa5LSU0bF6byEXOVeO0ebUQfztpjulbXh8TrBDSG+6VdxGtohPo2IYPBaXzGs3LOOor6An/lhptxBWdwYmf" +
"bcp0m8mnXZh1vN9rmbTsZXnhBIoPTaRDwUBi3vJ3Ms3iLaEm4S8Slrfmtht2jUjgGZ2vAeZ9OHU2YsGtrSpz6f\"}";
License license = License.fromSource(new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)),
XContentType.JSON);
assertThat(license.type(), equalTo("gold"));
assertThat(license.uid(), equalTo("4056779d-b823-4c12-a9cb-efa4a8d8c422"));
assertThat(license.issuer(), equalTo("elasticsearch"));
assertThat(license.issuedTo(), equalTo("customer"));
assertThat(license.expiryDate(), equalTo(1546596340459L));
assertThat(license.issueDate(), equalTo(1546589020459L));
}
public void testNotEnoughBytesFromXContent() throws Exception {
String licenseString = "{\"license\": " +
"{\"uid\":\"4056779d-b823-4c12-a9cb-efa4a8d8c422\"," +
"\"type\":\"gold\"," +
"\"issue_date_in_millis\":1546589020459," +
"\"expiry_date_in_millis\":1546596340459," +
"\"max_nodes\":5," +
"\"issued_to\":\"customer\"," +
"\"issuer\":\"elasticsearch\"," +
"\"signature\":\"AA\"}" +
"}";
ElasticsearchException exception =
expectThrows(ElasticsearchException.class,
() -> {
License.fromSource(new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)),
XContentType.JSON);
});
assertThat(exception.getMessage(), containsString("malformed signature for license [4056779d-b823-4c12-a9cb-efa4a8d8c422]"));
assertThat(exception.getCause(), instanceOf(BufferUnderflowException.class));
}
public void testMalformedSignatureFromXContent() throws Exception {
String licenseString = "{\"license\": " +
"{\"uid\":\"4056779d-b823-4c12-a9cb-efa4a8d8c422\"," +
"\"type\":\"gold\"," +
"\"issue_date_in_millis\":1546589020459," +
"\"expiry_date_in_millis\":1546596340459," +
"\"max_nodes\":5," +
"\"issued_to\":\"customer\"," +
"\"issuer\":\"elasticsearch\"," +
"\"signature\":\"" + randomAlphaOfLength(10) + "\"}" +
"}";
ElasticsearchException exception =
expectThrows(ElasticsearchException.class,
() -> {
License.fromSource(new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)),
XContentType.JSON);
});
}
public void testUnableToBase64DecodeFromXContent() throws Exception {
String licenseString = "{\"license\":" +
"{\"uid\":\"4056779d-b823-4c12-a9cb-efa4a8d8c422\"," +
"\"type\":\"gold\"," +
"\"issue_date_in_millis\":1546589020459," +
"\"expiry_date_in_millis\":1546596340459," +
"\"max_nodes\":5," +
"\"issued_to\":\"customer\"," +
"\"issuer\":\"elasticsearch\"," +
"\"signature\":\"AAAAAgAAAA34V2kfTJVtvdL2LttwAAABmFJ6NGRnbEM3WVQrZVQwNkdKQmR1VytlMTMyM1J0dTZ1WGwyY2ZCVFhqMGtJU2gzZ3pnNTVpOW" +
"F5Y1NaUkwyN2VsTEtCYnlZR2c5WWtjQ0phaDlhRjlDUXViUmUwMWhjSkE2TFcwSGdneTJHbUV4N2RHUWJxV20ybjRsZHRzV2xkN0ZmdDlYblJmNVcxMlBWeU81" +
"V1hLUm1EK0V1dmF3cFdlSGZzTU5SZE1qUmFra3JkS1hCanBWVmVTaFFwV3BVZERzeG9Sci9rYnlJK2toODZXY09tNmFHUVNUL3IyUHExV3VSTlBneWNJcFQ0bX" +
"l0cmhNNnRwbE1CWE4zWjJ5eGFuWFo0NGhsb3B5WFd1eTdYbFFWQkxFVFFPSlBERlB0eVVJYXVSZ0lsR2JpRS9rN1h4MSsvNUpOcGN6cU1NOHN1cHNtSTFIUGN1" +
"bWNGNEcxekhrblhNOXZ2VEQvYmRzQUFwbytUZEpRR3l6QU5oS2ZFSFdSbGxxNDZyZ0xvUHIwRjdBL2JqcnJnNGFlK09Cek9pYlJ5Umc9PQAAAQAth77fQLF7CC" +
"EL7wA6Z0/UuRm/weECcsjW/50kBnPLO8yEs+9/bPa5LSU0bF6byEXOVeO0ebUQfztpjulbXh8TrBDSG+6VdxGtohPo2IYPBaXzGs3LOOor6An/lhptxBWdwYmf" +
"+xHAQ8tyvRqP5G+PRU7tiluEwR/eyHGZV2exdJNzmoGzdPSWwueBM5HK2GexORICH+UFI4cuGz444/hL2MMM1RdpVWQkT0SJ6D9x/VuSmHuYPdtX59Pp41LXvl" +
"bcp0m8mnXZh1vN9rmbTsZXnhBIoPTaRDwUBi3vJ3Ms3iLaEm4S8Slrfmtht2jUjgGZ2vAeZ9OHU2YsGtrSpz6fd\"}";
ElasticsearchException exception =
expectThrows(ElasticsearchException.class,
() -> {
License.fromSource(new BytesArray(licenseString.getBytes(StandardCharsets.UTF_8)),
XContentType.JSON);
});
assertThat(exception.getMessage(), containsString("malformed signature for license [4056779d-b823-4c12-a9cb-efa4a8d8c422]"));
assertThat(exception.getCause(), instanceOf(IllegalArgumentException.class));
}
}