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

Allow using custom SSL certificates #8583

Merged
merged 48 commits into from
Mar 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b41dcb2
Design the preference section for adding custom SSL certificates
HoussemNasri Mar 19, 2022
529cef5
Inject custom certificates FXML views into the controller
HoussemNasri Mar 19, 2022
8bfb234
Delete unused import
HoussemNasri Mar 19, 2022
c0c0700
Allow for enabling or disabling custom certificates
HoussemNasri Mar 19, 2022
0ad15e6
Use LocalDate instead of LocalDateTime for tracking certificate validity
HoussemNasri Mar 19, 2022
c586be0
Populate CustomCertificateViewModel with data from SSLCertificate
HoussemNasri Mar 19, 2022
d382212
Setup cell factory and populate the table with dummy data
HoussemNasri Mar 19, 2022
63ee23f
Add '.cer' to StandardFileType
HoussemNasri Mar 19, 2022
e2cb0ca
Open file explorer on 'Add certificate' clicked
HoussemNasri Mar 19, 2022
17a78b1
Merge branch 'JabRef:main' into allow-custom-ssl
HoussemNasri Mar 19, 2022
4cf3683
Copy JDK 17 truststore into project resources
HoussemNasri Mar 19, 2022
e5b9972
Bump JavaFX from 17.0.2 to 18 (#8577)
calixtus Mar 17, 2022
f793ab9
Fix missing search index dir (#8581)
Siedlerchr Mar 17, 2022
eab1d2e
Log user added certificates information
HoussemNasri Mar 19, 2022
e3e9c11
Add an alias property to SSLCertificate that is generated randomly
HoussemNasri Mar 20, 2022
42a4f13
Merge remote-tracking branch 'origin/allow-custom-ssl' into allow-cus…
HoussemNasri Mar 20, 2022
d6a2372
Create TrustStoreManager for truststore manipulation
HoussemNasri Mar 20, 2022
ec92706
Add SSLPreferences
HoussemNasri Mar 20, 2022
5c21e62
Set custom certificate preferences defaults
HoussemNasri Mar 20, 2022
bcc65c0
Persist 'useCustomCertificate' boolean preference
HoussemNasri Mar 20, 2022
ae8ddd8
Use certificate thumbprint as an alias
HoussemNasri Mar 21, 2022
3b4abc1
Delete dummy certificates and use real imported certificate information
HoussemNasri Mar 21, 2022
b5a8884
Move certificate version formatting logic to the view
HoussemNasri Mar 21, 2022
fbb3bcc
Move TrustStoreManager from GUI to Logic
HoussemNasri Mar 21, 2022
9a37493
Use Integer to store version instead of primitive int
HoussemNasri Mar 21, 2022
9830eba
Persist thumbprint, version, validFrom and validTo columns
HoussemNasri Mar 21, 2022
a38cc5c
Use localized strings
HoussemNasri Mar 21, 2022
f84ee96
Fix failing test
HoussemNasri Mar 21, 2022
ca5a90f
Persist all certificate columns
HoussemNasri Mar 21, 2022
95e2b7f
Load truststore path from preferences
HoussemNasri Mar 21, 2022
ab987de
Deprecate bypassSSLVerification() and delete its usage
HoussemNasri Mar 21, 2022
f32baac
Set truststore path at startup
HoussemNasri Mar 21, 2022
051fcd6
Store truststore path in preference
HoussemNasri Mar 21, 2022
49c512a
Update CHANGELOG.md
HoussemNasri Mar 21, 2022
daa05e2
Add an icon to 'Add certificate' button
HoussemNasri Mar 21, 2022
768493a
Update truststore file on save preference
HoussemNasri Mar 21, 2022
fc9de9f
Clear all custom certificates from the truststore at preference reset
HoussemNasri Mar 21, 2022
0162133
Use truststore as the single source of truth
HoussemNasri Mar 22, 2022
d3a7a58
Merge branch 'main' into allow-custom-ssl
HoussemNasri Mar 22, 2022
4060f44
Show warning dialog on attempting to add a duplicate certificate
HoussemNasri Mar 22, 2022
d8b8958
Merge remote-tracking branch 'origin/allow-custom-ssl' into allow-cus…
HoussemNasri Mar 22, 2022
e41d126
Merge branch 'main' into allow-custom-ssl
HoussemNasri Mar 22, 2022
1b6f3ef
Stop allowing for toggling custom certificates usage
HoussemNasri Mar 26, 2022
c747317
Merge remote-tracking branch 'origin/allow-custom-ssl' into allow-cus…
HoussemNasri Mar 26, 2022
b04887b
Delete SSL certificates
HoussemNasri Mar 26, 2022
95e3b86
Merge branch 'main' into allow-custom-ssl
HoussemNasri Mar 26, 2022
10015d2
Fix failing test
HoussemNasri Mar 26, 2022
5f06abb
Merge remote-tracking branch 'origin/allow-custom-ssl' into allow-cus…
HoussemNasri Mar 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
### Added

- We added an extra option when right-clicking an entry in the Entry List to copy either the DOI or the DOI url.
- We added a new section to network preferences to allow using custom SSL certificates [#8126](https://github.com/JabRef/jabref/issues/8126)
- We improved the version check to take also beta version into account and now redirect to the right changelog for the version
- We added two new web and fulltext fetchers: SemanticScholar and ResearchGate

Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/jabref/gui/JabRefMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.jabref.logic.net.ProxyAuthenticator;
import org.jabref.logic.net.ProxyPreferences;
import org.jabref.logic.net.ProxyRegisterer;
import org.jabref.logic.net.URLDownload;
import org.jabref.logic.net.ssl.SSLPreferences;
import org.jabref.logic.protectedterms.ProtectedTermsLoader;
import org.jabref.logic.remote.RemotePreferences;
import org.jabref.logic.remote.client.RemoteClient;
Expand Down Expand Up @@ -51,7 +51,6 @@ public static void main(String[] args) {

@Override
public void start(Stage mainStage) {
URLDownload.bypassSSLVerification();
try {
FallbackExceptionHandler.installExceptionHandler();

Expand All @@ -63,6 +62,8 @@ public void start(Stage mainStage) {

configureProxy(preferences.getProxyPreferences());

configureSSL(preferences.getSSLPreferences());

Globals.startBackgroundTasks();

applyPreferences(preferences);
Expand Down Expand Up @@ -149,6 +150,11 @@ private static void configureProxy(ProxyPreferences proxyPreferences) {
}
}

private static void configureSSL(SSLPreferences sslPreferences) {
System.setProperty("javax.net.ssl.trustStore", sslPreferences.getTruststorePath());
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
}

private static void clearOldSearchIndices() {
Path currentIndexPath = BibDatabaseContext.getFulltextIndexBasePath();
Path appData = currentIndexPath.getParent();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package org.jabref.gui.preferences.network;

import java.time.LocalDate;
import java.util.Optional;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import org.jabref.gui.AbstractViewModel;
import org.jabref.logic.net.ssl.SSLCertificate;

public class CustomCertificateViewModel extends AbstractViewModel {
private final StringProperty serialNumberProperty = new SimpleStringProperty("");
private final StringProperty issuerProperty = new SimpleStringProperty("");
private final ObjectProperty<LocalDate> validFromProperty = new SimpleObjectProperty<>();
private final ObjectProperty<LocalDate> validToProperty = new SimpleObjectProperty<>();
private final StringProperty signatureAlgorithmProperty = new SimpleStringProperty("");
private final StringProperty versionProperty = new SimpleStringProperty("");
private final StringProperty thumbprintProperty = new SimpleStringProperty("");
private final StringProperty pathProperty = new SimpleStringProperty("");

public CustomCertificateViewModel(String thumbprint, String serialNumber, String issuer, LocalDate validFrom, LocalDate validTo, String sigAlgorithm, String version) {
serialNumberProperty.setValue(serialNumber);
issuerProperty.setValue(issuer);
validFromProperty.setValue(validFrom);
validToProperty.setValue(validTo);
signatureAlgorithmProperty.setValue(sigAlgorithm);
versionProperty.setValue(version);
thumbprintProperty.setValue(thumbprint);
}

public ReadOnlyStringProperty serialNumberProperty() {
return serialNumberProperty;
}

public ReadOnlyStringProperty issuerProperty() {
return issuerProperty;
}

public ReadOnlyObjectProperty<LocalDate> validFromProperty() {
return validFromProperty;
}

public ReadOnlyObjectProperty<LocalDate> validToProperty() {
return validToProperty;
}

public ReadOnlyStringProperty signatureAlgorithmProperty() {
return signatureAlgorithmProperty;
}

public ReadOnlyStringProperty versionProperty() {
return versionProperty;
}

public String getVersion() {
return versionProperty.getValue();
}

public String getThumbprint() {
return thumbprintProperty.getValue();
}

public LocalDate getValidFrom() {
return validFromProperty.getValue();
}

public LocalDate getValidTo() {
return validToProperty.getValue();
}

public StringProperty pathPropertyProperty() {
return pathProperty;
}

public Optional<String> getPath() {
if (pathProperty.getValue() == null || pathProperty.getValue().isEmpty()) {
return Optional.empty();
} else {
return Optional.of(pathProperty.getValue());
}
}

public CustomCertificateViewModel setPath(String path) {
pathProperty.setValue(path);
return this;
}

public String getSerialNumber() {
return serialNumberProperty.getValue();
}

public String getIssuer() {
return issuerProperty.getValue();
}

public String getSignatureAlgorithm() {
return signatureAlgorithmProperty.getValue();
}

public static CustomCertificateViewModel fromSSLCertificate(SSLCertificate sslCertificate) {
return new CustomCertificateViewModel(
sslCertificate.getSHA256Thumbprint(),
sslCertificate.getSerialNumber(),
sslCertificate.getIssuer(),
sslCertificate.getValidFrom(),
sslCertificate.getValidTo(),
sslCertificate.getSignatureAlgorithm(),
sslCertificate.getVersion().toString());
}
}
172 changes: 135 additions & 37 deletions src/main/java/org/jabref/gui/preferences/network/NetworkTab.fxml
Original file line number Diff line number Diff line change
@@ -1,59 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import org.controlsfx.control.textfield.CustomPasswordField?>
<fx:root spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jabref.gui.preferences.network.NetworkTab">
<Label styleClass="titleHeader" text="%Network"/>
<Label styleClass="sectionHeader" text="%Remote operation"/>
<Label fx:id="remoteLabel"
text="%This feature lets new files be opened or imported into an already running instance of JabRef instead of opening a new instance. For instance, this is useful when you open a file in JabRef from your web browser. Note that this will prevent you from running more than one instance of JabRef at a time."
textOverrun="CLIP" wrapText="true"/>

<?import org.jabref.gui.icon.JabRefIconView?>
<fx:root spacing="10.0" type="VBox" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jabref.gui.preferences.network.NetworkTab">
<Label styleClass="titleHeader" text="%Network" />
<Label styleClass="sectionHeader" text="%Remote operation" />
<Label fx:id="remoteLabel" text="%This feature lets new files be opened or imported into an already running instance of JabRef instead of opening a new instance. For instance, this is useful when you open a file in JabRef from your web browser. Note that this will prevent you from running more than one instance of JabRef at a time." textOverrun="CLIP" wrapText="true" />
<HBox alignment="CENTER_LEFT" spacing="10.0">
<CheckBox fx:id="remoteServer" text="%Listen for remote operation on port"/>
<TextField fx:id="remotePort" maxWidth="100.0" HBox.hgrow="ALWAYS"/>
<Button fx:id="remoteHelp" prefWidth="20.0"/>
<CheckBox fx:id="remoteServer" text="%Listen for remote operation on port" />
<TextField fx:id="remotePort" maxWidth="100.0" HBox.hgrow="ALWAYS" />
<Button fx:id="remoteHelp" prefWidth="20.0" />
</HBox>

<Label styleClass="sectionHeader" text="%Proxy configuration"/>
<Label styleClass="sectionHeader" text="%Proxy configuration" />
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES"/>
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints />
<RowConstraints />
</rowConstraints>
<CheckBox fx:id="proxyUse" text="%Use custom proxy configuration" GridPane.columnSpan="3" GridPane.rowIndex="0" />
<Label fx:id="proxyHostnameLabel" text="%Hostname" GridPane.rowIndex="1" />
<TextField fx:id="proxyHostname" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label fx:id="proxyPortLabel" text="%Port" GridPane.rowIndex="2" />
<TextField fx:id="proxyPort" maxWidth="100.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<CheckBox fx:id="proxyUseAuthentication" text="%Proxy requires authentication" GridPane.columnSpan="3" GridPane.rowIndex="3" />
<Label fx:id="proxyUsernameLabel" text="%Username" GridPane.rowIndex="4" />
<TextField fx:id="proxyUsername" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label fx:id="proxyPasswordLabel" text="%Password" GridPane.rowIndex="5" />
<CustomPasswordField fx:id="proxyPassword" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Label fx:id="proxyAttentionLabel" styleClass="warning-message" text="%Attention: Password is stored in plain text!" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<Button fx:id="checkConnectionButton" onAction="#checkConnection" prefWidth="200.0" text="%Check connection" GridPane.columnIndex="1" GridPane.rowIndex="6" />
</GridPane>
<Label styleClass="sectionHeader" text="%SSL Configuration" />
<GridPane
hgap="10.0"
vgap="10.0">
<columnConstraints>
<ColumnConstraints
hgrow="SOMETIMES"/>
<ColumnConstraints
hgrow="SOMETIMES"/>
<ColumnConstraints
hgrow="SOMETIMES"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints
minHeight="10.0"
vgrow="SOMETIMES"/>
<RowConstraints/>
<RowConstraints/>
</rowConstraints>
<CheckBox fx:id="proxyUse" text="%Use custom proxy configuration" GridPane.columnSpan="3"
GridPane.rowIndex="0"/>
<Label fx:id="proxyHostnameLabel" text="%Hostname" GridPane.rowIndex="1"/>
<TextField fx:id="proxyHostname" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label fx:id="proxyPortLabel" text="%Port" GridPane.rowIndex="2"/>
<TextField fx:id="proxyPort" maxWidth="100.0" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<CheckBox fx:id="proxyUseAuthentication" text="%Proxy requires authentication" GridPane.columnSpan="3"
GridPane.rowIndex="3"/>
<Label fx:id="proxyUsernameLabel" text="%Username" GridPane.rowIndex="4"/>
<TextField fx:id="proxyUsername" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
<Label fx:id="proxyPasswordLabel" text="%Password" GridPane.rowIndex="5"/>
<CustomPasswordField fx:id="proxyPassword" prefWidth="200.0" GridPane.columnIndex="1"
GridPane.rowIndex="5"/>
<Label fx:id="proxyAttentionLabel" styleClass="warning-message"
text="%Attention: Password is stored in plain text!" GridPane.columnIndex="2" GridPane.rowIndex="5"/>
<Button fx:id="checkConnectionButton" text="%Check connection" onAction="#checkConnection"
prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6"/>
<TableView
fx:id="customCertificatesTable"
prefHeight="200.0"
GridPane.columnSpan="3"
GridPane.rowIndex="0">
<GridPane.margin>
<Insets right="16.0"/>
</GridPane.margin>
<columns>
<TableColumn
fx:id="certSerialNumber"
prefWidth="75.0"
text="%Serial number"/>
<TableColumn
fx:id="certIssuer"
prefWidth="75.0"
text="%Issuer"/>
<TableColumn
fx:id="certValidFrom"
prefWidth="50.0"
text="%Valid from"/>
<TableColumn
fx:id="certValidTo"
prefWidth="50.0"
text="%Valid to"/>
<TableColumn
fx:id="certSignatureAlgorithm"
minWidth="40.0"
prefWidth="100.0"
text="%Signature algorithm"/>
<TableColumn
fx:id="certVersion"
prefWidth="136.0"
text="%Version"/>
<TableColumn
fx:id="actionsColumn" maxWidth="35.0" minWidth="35.0" prefWidth="35.0"
editable="false" resizable="false" reorderable="false"
/>
</columns>
<columnResizePolicy>
<TableView
fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
<Button fx:id="addCertificate"
mnemonicParsing="false"
onAction="#addCertificateFile"
text="%Add certificate"
GridPane.columnIndex="2"
GridPane.halignment="RIGHT"
GridPane.rowIndex="1"
GridPane.valignment="TOP">
<GridPane.margin>
<Insets right="16.0"/>
</GridPane.margin>
<graphic>
<JabRefIconView glyph="OPEN_LIST"/>
</graphic>
</Button>
</GridPane>
</fx:root>
Loading