Skip to content

Commit

Permalink
Merge pull request #174 from zlamalp/sshkeys
Browse files Browse the repository at this point in the history
feat(registrar): support better SSH keys input validation
  • Loading branch information
zlamalp authored Jan 10, 2022
2 parents aba112f + 9edd223 commit e2e9a2b
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,33 @@ public interface PerunRegistrarTranslation extends PerunTranslation {
@DefaultMessage("Type to search...")
String typeToSearch();

@DefaultMessage("Key \"<i>{0}</i>\" does not have the correct format.")
String sshKeyFormat(String key);

@DefaultMessage("Do not mix commas and new-lines as SSH keys separators.")
String mixingNewlinesWithCommas();

@DefaultMessage("Multiple consecutive commas are not allowed, use a single comma or newline as a separator between SSH keys.")
String tooMuchCommas();

@DefaultMessage("Multiple consecutive commas are not allowed, use a single comma as a separator between SSH keys.")
String tooMuchCommasTextField();

@DefaultMessage("Multiple consecutive newlines are not allowed, use one newline or comma as a separator between SSH keys.")
String tooMuchNewlines();

@DefaultMessage("Missing separator between the SSH keys (comma or newline).")
String sshKeyMissingDelimiter();

@DefaultMessage("Missing comma as a separator between the SSH keys.")
String sshKeyMissingCommaDelimiterTextField();

@DefaultMessage("No spaces are allowed around the SSH key separator (comma or newline).")
String sshKeyNoSpaceAroundKeySeparator();

@DefaultMessage("No spaces are allowed around the SSH key separator (comma).")
String sshKeyNoSpaceAroundCommasTextField();

// -------------- SUBMITTED APPS PAGE ------------------------ //

@DefaultMessage("Submitted registrations")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import cz.metacentrum.perun.wui.model.beans.ApplicationFormItemData;
import cz.metacentrum.perun.wui.registrar.widgets.PerunForm;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.PerunFormItemValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.SshKeysTextAreaValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.TextAreaValidator;
import cz.metacentrum.perun.wui.widgets.boxes.ExtendedTextArea;
import org.gwtbootstrap3.client.ui.html.Paragraph;
Expand All @@ -25,7 +26,13 @@ public class TextArea extends PerunFormItemEditable {

public TextArea(PerunForm form, ApplicationFormItemData item, String lang) {
super(form, item, lang);
this.validator = new TextAreaValidator();

if ("urn:perun:user:attribute-def:def:sshPublicKey".equals(item.getFormItem().getPerunDestinationAttribute())) {
this.validator = new SshKeysTextAreaValidator();
} else {
this.validator = new TextAreaValidator();
}

}

protected Widget initWidget() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import cz.metacentrum.perun.wui.model.beans.ApplicationFormItemData;
import cz.metacentrum.perun.wui.registrar.widgets.PerunForm;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.PerunFormItemValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.SshKeysTextFieldValidator;
import cz.metacentrum.perun.wui.registrar.widgets.items.validators.TextFieldValidator;
import cz.metacentrum.perun.wui.widgets.boxes.ExtendedTextBox;
import org.gwtbootstrap3.client.ui.constants.ColumnSize;
Expand All @@ -28,7 +29,11 @@ public class TextField extends PerunFormItemEditable {

public TextField(PerunForm form, ApplicationFormItemData item, String lang) {
super(form, item, lang);
this.validator = new TextFieldValidator();
if ("urn:perun:user:attribute-def:def:sshPublicKey".equals(item.getFormItem().getPerunDestinationAttribute())) {
this.validator = new SshKeysTextFieldValidator();
} else {
this.validator = new TextFieldValidator();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package cz.metacentrum.perun.wui.registrar.widgets.items.validators;

import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import cz.metacentrum.perun.wui.registrar.widgets.items.TextArea;
import org.gwtbootstrap3.client.ui.constants.ValidationState;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Pavel Zlámal <[email protected]>
*/
public class SshKeysTextAreaValidator extends TextAreaValidator {

RegExp regExp = RegExp.compile("^(" +
"(ssh-(rsa|dss|ed25519)([email protected])?)|" +
"(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)[email protected])|" +
"(ecdsa-sha2-nistp(256|384|521)([email protected])?))" +
" (([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?)( [^,\n]+)?$");

@Override
public boolean validateLocal(TextArea textArea) {

if (textArea.isRequired() && isNullOrEmpty(textArea.getValue())) {
setResult(Result.EMPTY);
textArea.setRawStatus(getTransl().cantBeEmpty(), ValidationState.ERROR);
return false;
}

if (!textArea.getBox().isValid()) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getErrorMsgOrDefault(textArea), ValidationState.ERROR);
return false;
}

if (textArea.getValue() != null && textArea.getValue().length() > textArea.MAX_LENGTH) {
setResult(Result.TOO_LONG);
textArea.setStatus(getTransl().tooLong(), ValidationState.ERROR);
return false;
}

if (textArea.getValue() != null && !textArea.getValue().isEmpty()) {

String sshKeys = textArea.getValue();

if (sshKeys.contains(",,")) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getTransl().tooMuchCommas(), ValidationState.ERROR);
return false;
}

if (sshKeys.contains("\n\n")) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getTransl().tooMuchNewlines(), ValidationState.ERROR);
return false;
}

if (sshKeys.contains(",") && sshKeys.contains("\n")) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getTransl().mixingNewlinesWithCommas(), ValidationState.ERROR);
return false;
}

if (sshKeys.contains(", ") || sshKeys.contains(" ,") || sshKeys.contains("\n ") || sshKeys.contains(" \n")) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getTransl().sshKeyNoSpaceAroundKeySeparator(), ValidationState.ERROR);
return false;
}

// FIXME - this doesn't make sense anymore, as we have multiple different SSH keys prefixes, which needs to be checked.
/*
if (sshKeys.indexOf("ssh-") != sshKeys.lastIndexOf("ssh-")) {
// there are at least two keys
if (!sshKeys.contains(",ssh-") && !sshKeys.contains("\nssh-")) {
setResult(Result.INVALID_FORMAT);
textArea.setStatus(getTransl().sshKeyMissingDelimiter(), ValidationState.ERROR);
return false;
}
}
*/

// normalize value just in case
sshKeys = sshKeys.replaceAll("(\n)+", ",");
sshKeys = sshKeys.replaceAll("(,)+", ",");
List<String> keys = Arrays.stream(sshKeys.split(",")).collect(Collectors.toList());

for (String key : keys) {
MatchResult matcher = regExp.exec(key);
if (matcher == null) {
int length = Math.min(key.length(), 30);
textArea.setRawStatus(getTransl().sshKeyFormat(key.substring(0, length)+((length == 30) ? "..." : "")), ValidationState.ERROR);
setResult(Result.INVALID_FORMAT);
return false;
}
}

}

textArea.setStatus(ValidationState.SUCCESS);
return true;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package cz.metacentrum.perun.wui.registrar.widgets.items.validators;

import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import cz.metacentrum.perun.wui.registrar.widgets.items.TextField;
import org.gwtbootstrap3.client.ui.constants.ValidationState;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Pavel Zlámal <[email protected]>
*/
public class SshKeysTextFieldValidator extends TextFieldValidator {

RegExp regExp = RegExp.compile("^(" +
"(ssh-(rsa|dss|ed25519)([email protected])?)|" +
"(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)[email protected])|" +
"(ecdsa-sha2-nistp(256|384|521)([email protected])?))" +
" (([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?)( [^,\n]+)?$");

@Override
public boolean validateLocal(TextField textField) {

if (textField.isRequired() && isNullOrEmpty(textField.getValue())) {
setResult(Result.EMPTY);
textField.setRawStatus(getTransl().cantBeEmpty(), ValidationState.ERROR);
return false;
}

if (!textField.getBox().isValid()) {
setResult(Result.INVALID_FORMAT);
textField.setStatus(getErrorMsgOrDefault(textField), ValidationState.ERROR);
return false;
}

if (textField.getValue() != null && textField.getValue().length() > textField.MAX_LENGTH) {
setResult(Result.TOO_LONG);
textField.setStatus(getTransl().tooLong(), ValidationState.ERROR);
return false;
}

if (textField.getValue() != null && !textField.getValue().isEmpty()) {

String sshKeys = textField.getValue();

if (sshKeys.contains(",,")) {
setResult(Result.INVALID_FORMAT);
textField.setStatus(getTransl().tooMuchCommasTextField(), ValidationState.ERROR);
return false;
}

if (sshKeys.contains(", ") || sshKeys.contains(" ,")) {
setResult(Result.INVALID_FORMAT);
textField.setStatus(getTransl().sshKeyNoSpaceAroundCommasTextField(), ValidationState.ERROR);
return false;
}

// FIXME - this doesn't make sense anymore, as we have multiple different SSH keys prefixes, which needs to be checked.
/*
if (sshKeys.indexOf("ssh-") != sshKeys.lastIndexOf("ssh-")) {
// there are at least two keys
if (!sshKeys.contains(",ssh-")) {
setResult(Result.INVALID_FORMAT);
textField.setStatus(getTransl().sshKeyMissingCommaDelimiterTextField(), ValidationState.ERROR);
return false;
}
}
*/

// normalize value just in case
sshKeys = sshKeys.replaceAll("(,)+", ",");
List<String> keys = Arrays.stream(sshKeys.split(",")).collect(Collectors.toList());

for (String key : keys) {
MatchResult matcher = regExp.exec(key);
if (matcher == null) {
int length = Math.min(key.length(), 30);
textField.setRawStatus(getTransl().sshKeyFormat(key.substring(0, length)+((length == 30) ? "..." : "")), ValidationState.ERROR);
setResult(Result.INVALID_FORMAT);
return false;
}
}

}

textField.setStatus(ValidationState.SUCCESS);
return true;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ federation=<i>hodnota ověřena Poskytovatelem identity</i>
undefinedFormItem=NEDEFINOVANÝ
clearRadiobox=žádný z předchozích
typeToSearch=Hledej psaním...
sshKeyFormat=Klíč "<i>{0}</i>" nemá správný formát.
mixingNewlinesWithCommas=Nemíchejte čárky a nové řádky jako oddělovače SSH klíčů.
tooMuchCommas=Více čárek za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jednu čárku nebo nový řádek.
tooMuchCommasTextField=Více čárek za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jednu čárku.
tooMuchNewlines=Více nových řádků za sebou není dovoleno, jako oddělovač mezi SSH klíči používejte jeden nový řádek nebo čárku.
sshKeyMissingDelimiter=Mezi SSH klíči chybí oddělovač (čárka nebo nový řádek).
sshKeyMissingCommaDelimiterTextField=Mezi SSH klíči chybí oddělovač (čárka).
sshKeyNoSpaceAroundKeySeparator=Kolem oddělovače SSH klíčů (čárky nebo nového řádku) nejsou dovoleny mezery.
sshKeyNoSpaceAroundCommasTextField=Kolem oddělovače SSH klíčů (čárky) nejsou dovoleny mezery.

# // -------------- SUBMITTED APPS PAGE ------------------------ //

Expand Down

0 comments on commit e2e9a2b

Please sign in to comment.