Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate endpoints #76

Merged
merged 12 commits into from
Jan 13, 2023
30 changes: 30 additions & 0 deletions dil/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,36 @@
<artifactId>utils</artifactId>
<version>${assimbly.version}</version>
</dependency>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two remarks:

  • For Assimbly the scope cannot be 'provided'. In Karaf this is used because the dependencies are injected by Karaf into runtime. In Assimbly the dependencies are provided in compile time.
  • Maybe it's good to check if these dependencies aren't already provided by the base repository or add them there. The reason is that dependencies can be managed centrally in one list in the base.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>${groovy-script.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-jsr223</artifactId>
<version>${groovy-script.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-dateutil</artifactId>
<version>${groovy-script.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>${commons-net.version}</version>
</dependency>
</dependencies>

<build>
Expand Down
23 changes: 23 additions & 0 deletions dil/src/main/java/org/assimbly/dil/validation/CronValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.assimbly.dil.validation;

import org.assimbly.util.error.ValidationErrorMessage;
import org.quartz.CronExpression;

public class CronValidator {

private static final ValidationErrorMessage EMPTY_CRON_ERROR = new ValidationErrorMessage("Empty crons aren't allowed!");

public ValidationErrorMessage validate(String cronExpression) {

if (cronExpression.isEmpty())
return EMPTY_CRON_ERROR;

try {
new CronExpression(cronExpression);
} catch (Exception e) {
return new ValidationErrorMessage("Cron Validation error: " + e.getMessage());
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.assimbly.dil.validation;

import org.assimbly.dil.validation.beans.Expression;
import org.assimbly.dil.validation.expressions.*;
import org.assimbly.util.error.ValidationErrorMessage;

import java.util.ArrayList;
import java.util.List;

public class ExpressionsValidator {

private static final ValidationErrorMessage EMPTY_EXPRESSION_ERROR = new ValidationErrorMessage("Empty expressions aren't allowed!");

private JsonPathValidator jsonPathValidator = new JsonPathValidator();
private SimpleValidator simpleValidator = new SimpleValidator();
private XPathValidator xpathValidator = new XPathValidator();
private ConstantValidator constantValidator = new ConstantValidator();
private GroovyValidator groovyValidator = new GroovyValidator();

public List<ValidationErrorMessage> validate(List<Expression> expressions) {

List<ValidationErrorMessage> validationErrors = new ArrayList<>();

if (expressions.isEmpty()) {
validationErrors.add(EMPTY_EXPRESSION_ERROR);
return validationErrors;
}

for (Expression expression : expressions) {
ValidationErrorMessage error;

switch(expression.getExpressionType()) {
case "constant":
error = constantValidator.validate(expression);
break;
case "groovy":
error = groovyValidator.validate(expression);
break;
case "jsonpath":
error = jsonPathValidator.validate(expression);
break;
case "simple":
error = simpleValidator.validate(expression);
break;
case "xpath":
error = xpathValidator.validate(expression);
break;
default:
throw new RuntimeException("Dovetail could not validate the type of expression submitted.");
}

if (error != null) {
validationErrors.add(error);
}
}

if (validationErrors.isEmpty())
return null;

return validationErrors;
}
}
162 changes: 162 additions & 0 deletions dil/src/main/java/org/assimbly/dil/validation/FtpValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package org.assimbly.dil.validation;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.assimbly.dil.validation.beans.FtpSettings;
import org.assimbly.util.error.ValidationErrorMessage;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.ConnectException;
import java.net.UnknownHostException;

public class FtpValidator {

private static final int TIMEOUT = 3000;
private static final ValidationErrorMessage UNREACHABLE_ERROR =
new ValidationErrorMessage("Cannot login into FTP from the Dovetail server!");

public ValidationErrorMessage validate(FtpSettings ftpSettings) {

if (ftpSettings.getProtocol().equalsIgnoreCase("ftp"))
return checkFtpConnection(ftpSettings.getUser(), ftpSettings.getPwd(), ftpSettings.getHost(), ftpSettings.getPort(), false);
else if (ftpSettings.getProtocol().equalsIgnoreCase("ftps"))
return checkFtpConnection(ftpSettings.getUser(), ftpSettings.getPwd(), ftpSettings.getHost(), ftpSettings.getPort(), true);
else
return checkSFtpConnection(ftpSettings.getUser(), ftpSettings.getPwd(), ftpSettings.getHost(), ftpSettings.getPort(), ftpSettings.getPkf(), ftpSettings.getPkfd());
}

private Session setupDefaultSession(JSch jsch, String userName, String host, int port) throws JSchException {
Session session = jsch.getSession(userName, host, port);
session.setConfig("StrictHostKeyChecking", "no");

return session;
}

private ValidationErrorMessage checkSFtpConnection(String userName, String password, String host, int port, String privateKeyFilePath, String privateKeyFileData) {
Session session = null;
Channel channel = null;
File tempFile = null;
JSch jsch;

try {
jsch = new JSch();

session = setupDefaultSession(jsch, userName, host, port);

if (password != null && !password.isEmpty())
session.setPassword(password);

if (privateKeyFileData != null && !privateKeyFileData.isEmpty()) {
tempFile = File.createTempFile("temp", "");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))){
writer.write(privateKeyFileData);
}
jsch.addIdentity(tempFile.getAbsolutePath());
}
else if (privateKeyFilePath != null && !privateKeyFilePath.isEmpty())
jsch.addIdentity(privateKeyFilePath);

session.connect(TIMEOUT);

channel = session.openChannel("sftp");
channel.connect();

if (!channel.isConnected())
return UNREACHABLE_ERROR;

} catch (Exception e) {
return handleSftpException(e);
} finally {
if (channel != null)
channel.disconnect();
if (session != null)
session.disconnect();
if (tempFile != null)
tempFile.delete();
}

return null;
}

private ValidationErrorMessage handleSftpException (Exception exception) {
Throwable cause = exception.getCause();

if (cause != null) {
return getMessageFromCause(cause);
} else {
return getMessageFromException(exception);
}
}

private ValidationErrorMessage getMessageFromCause (Throwable cause) {
if (cause instanceof ConnectException) {
return new ValidationErrorMessage("Connection refused");
} else if (cause instanceof UnknownHostException) {
return new ValidationErrorMessage("Host name could not be resolved");
} else {
return new ValidationErrorMessage(cause.getMessage());
}
}

private ValidationErrorMessage getMessageFromException (Exception exception) {
if (exception.getMessage().contains("ConnectException")) {
return new ValidationErrorMessage("Connection refused");
} else if (exception.getMessage().contains("UnknownHostException")) {
return new ValidationErrorMessage("Host name could not be resolved");
} else {
return new ValidationErrorMessage(exception.getMessage());
}
}

private ValidationErrorMessage checkFtpConnection(String userName, String password, String host, int port, boolean secure) {
FTPClient ftp = null;

try {
if(secure) {
ftp = new FTPSClient();
} else {
ftp = new FTPClient();
}

ftp.connect(host, port);

// After connection attempt, you should check the reply code to verify success.
int reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();

return UNREACHABLE_ERROR;
}

if (!ftp.login(userName, password)) {
ftp.logout();

return UNREACHABLE_ERROR;
}
} catch (ConnectException e){
return new ValidationErrorMessage("Connection refused");
} catch (UnknownHostException e) {
return new ValidationErrorMessage("Host name could not be resolved");
} catch (Exception e) {
return new ValidationErrorMessage(e.getMessage());
} finally {
if (ftp != null && ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
// Do nothing
}
}
}

return null;
}
}
34 changes: 34 additions & 0 deletions dil/src/main/java/org/assimbly/dil/validation/RegexValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.assimbly.dil.validation;

import org.assimbly.dil.validation.beans.Regex;
import org.assimbly.util.error.ValidationErrorMessage;

import java.util.AbstractMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class RegexValidator {

public AbstractMap.SimpleEntry validate(Regex expression) {

AbstractMap.SimpleEntry<Integer, String> response = null;
String regex = expression.getExpression();

if (regex.isEmpty()) {
return new AbstractMap.SimpleEntry(-1, "Regex cannot be empty");
}

try {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("");
response = new AbstractMap.SimpleEntry(1, String.valueOf(matcher.groupCount()));

} catch (PatternSyntaxException e) {
response = new AbstractMap.SimpleEntry(-1, e.getMessage());
}

return response;
}

}
50 changes: 50 additions & 0 deletions dil/src/main/java/org/assimbly/dil/validation/UrlValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.assimbly.dil.validation;

import org.assimbly.util.error.ValidationErrorMessage;

import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UrlValidator {

private static final int TIMEOUT = 5000;
private static final ValidationErrorMessage UNREACHABLE_ERROR = new ValidationErrorMessage("Url is not reachable from the server!");
private static final ValidationErrorMessage INVALID_URL_ERROR = new ValidationErrorMessage("Url is not valid!");

public ValidationErrorMessage validate(String url) {
final HttpURLConnection httpUrlConn;

try {
String decodedUrl = URLDecoder.decode(url, "UTF-8");

if(!validateURL(decodedUrl))
return INVALID_URL_ERROR;

httpUrlConn = (HttpURLConnection) new URL(decodedUrl).openConnection();

httpUrlConn.setRequestMethod("HEAD");

// Set timeouts in milliseconds
httpUrlConn.setConnectTimeout(TIMEOUT);
httpUrlConn.connect();
//need to trigger exception when no connection can be established
httpUrlConn.getResponseMessage();
} catch (UnknownHostException e) {
return UNREACHABLE_ERROR;
} catch (Exception e) {
return new ValidationErrorMessage(e.getMessage());
}

return null;
}

public static final boolean validateURL(String url) {
Pattern regex = Pattern.compile("^(https?):\\/\\/[-a-zA-Z0-9+&@#\\/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#\\/%=~_|]");
Matcher matcher = regex.matcher(url);
return matcher.find();
}
}
9 changes: 9 additions & 0 deletions dil/src/main/java/org/assimbly/dil/validation/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.assimbly.dil.validation;

import org.assimbly.dil.validation.beans.Expression;
import org.assimbly.util.error.ValidationErrorMessage;

public interface Validator {

ValidationErrorMessage validate(Expression expression);
}
Loading