diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java index fcb2d7e6..74caf565 100644 --- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java +++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation.java @@ -208,6 +208,33 @@ public interface PerunRegistrarTranslation extends PerunTranslation { @DefaultMessage("Type to search...") String typeToSearch(); + @DefaultMessage("Key \"{0}\" 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") diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java index 4aa9c67e..8e7c7062 100644 --- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java +++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextArea.java @@ -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; @@ -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() { diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java index 6cd3a09a..0a244c8c 100644 --- a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java +++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/TextField.java @@ -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; @@ -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 diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java new file mode 100644 index 00000000..17e013de --- /dev/null +++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextAreaValidator.java @@ -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 + */ +public class SshKeysTextAreaValidator extends TextAreaValidator { + + RegExp regExp = RegExp.compile("^(" + + "(ssh-(rsa|dss|ed25519)(-cert-v01@openssh.com)?)|" + + "(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)?@openssh.com)|" + + "(ecdsa-sha2-nistp(256|384|521)(-cert-v01@openssh.com)?))" + + " (([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 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; + + } + +} diff --git a/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java new file mode 100644 index 00000000..16a0d999 --- /dev/null +++ b/perun-wui-registrar/src/main/java/cz/metacentrum/perun/wui/registrar/widgets/items/validators/SshKeysTextFieldValidator.java @@ -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 + */ +public class SshKeysTextFieldValidator extends TextFieldValidator { + + RegExp regExp = RegExp.compile("^(" + + "(ssh-(rsa|dss|ed25519)(-cert-v01@openssh.com)?)|" + + "(sk-(ssh-ed25519|ecdsa-sha2-nistp256)(-cert-v01)?@openssh.com)|" + + "(ecdsa-sha2-nistp(256|384|521)(-cert-v01@openssh.com)?))" + + " (([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 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; + + } + +} diff --git a/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties b/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties index 2afcb75e..50fd2463 100644 --- a/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties +++ b/perun-wui-registrar/src/main/resources/cz/metacentrum/perun/wui/registrar/client/resources/PerunRegistrarTranslation_cs.properties @@ -78,6 +78,15 @@ federation=hodnota ověřena Poskytovatelem identity undefinedFormItem=NEDEFINOVANÝ clearRadiobox=žádný z předchozích typeToSearch=Hledej psaním... +sshKeyFormat=Klíč "{0}" 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 ------------------------ //