From 808ee62ac9c3dd402fd3c88c00a486c7757d5897 Mon Sep 17 00:00:00 2001 From: georgweiss Date: Thu, 11 Sep 2025 12:56:34 +0200 Subject: [PATCH 01/11] Minor improvements to the credentials management app --- .../CredentialsManagementController.java | 33 ++++++++++---- .../CredentialsManagementStage.java | 1 - .../css/credentials-management-style.css | 8 +++- .../CredentialsManagement.fxml | 2 +- .../OlogAuthenticationScope.java | 20 +++++++++ .../OlogServiceAuthenticationProvider.java | 8 +++- .../phoebus/olog/es/api/OlogHttpClient.java | 3 +- .../olog/api/OlogAuthenticationScope.java | 20 +++++++++ .../java/org/phoebus/olog/api/OlogClient.java | 2 +- .../olog/ui/LogEntryTableViewController.java | 3 +- .../ui/write/LogEntryEditorController.java | 6 ++- .../SaveAndRestoreAuthenticationProvider.java | 9 +++- .../SaveAndRestoreAuthenticationScope.java | 19 ++++++++ .../client/SaveAndRestoreClientImpl.java | 3 +- .../ui/ContextMenuCreateSaveset.java | 6 +-- .../ui/SaveAndRestoreBaseController.java | 8 ++-- .../phoebus/security/store/SecureStore.java | 45 +++++++++++++------ .../security/tokens/AuthenticationScope.java | 44 ++++++------------ .../tokens/ScopedAuthenticationToken.java | 4 +- .../tokens/ScopedAuthenticationTokenTest.java | 30 ++++++++++--- .../css/credentials-management-style.css | 20 --------- 21 files changed, 193 insertions(+), 101 deletions(-) create mode 100644 app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogAuthenticationScope.java create mode 100644 app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogAuthenticationScope.java create mode 100644 app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationScope.java delete mode 100644 core/ui/src/main/resources/css/credentials-management-style.css diff --git a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java index 1aa73f5786..03ef1d148d 100644 --- a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java +++ b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java @@ -53,22 +53,28 @@ */ public class CredentialsManagementController { + @SuppressWarnings("unused") @FXML private Node parent; + @SuppressWarnings("unused") @FXML private TableView tableView; + @SuppressWarnings("unused") @FXML private TableColumn actionButtonColumn; + @SuppressWarnings("unused") @FXML private TableColumn usernameColumn; + @SuppressWarnings("unused") @FXML private TableColumn passwordColumn; + @SuppressWarnings("unused") @FXML private Button clearAllCredentialsButton; - + @SuppressWarnings("unused") @FXML - private TableColumn scopeColumn; + private TableColumn scopeColumn; private final SimpleBooleanProperty listEmpty = new SimpleBooleanProperty(true); private final ObservableList serviceItems = @@ -84,10 +90,11 @@ public CredentialsManagementController(List authe this.secureStore = secureStore; } + @SuppressWarnings("unused") @FXML public void initialize() { - tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + tableView.getStylesheets().add(getClass().getResource("/css/credentials-management-style.css").toExternalForm()); clearAllCredentialsButton.disableProperty().bind(listEmpty); Callback, TableCell> actionColumnCellFactory = new Callback<>() { @Override @@ -129,9 +136,12 @@ public void updateItem(Void o, boolean empty) { usernameColumn.setCellFactory(c -> new UsernameTableCell()); passwordColumn.setCellFactory(c -> new PasswordTableCell()); + scopeColumn.setStyle( "-fx-alignment: CENTER-LEFT;"); + updateTable(); } + @SuppressWarnings("unused") @FXML public void logOutFromAll() { try { @@ -181,19 +191,19 @@ private void updateTable() { // Match saved tokens with an authentication provider, where applicable List serviceItems = savedTokens.stream().map(token -> { ServiceAuthenticationProvider provider = - authenticationProviders.stream().filter(p-> p.getAuthenticationScope().equals(token.getAuthenticationScope())).findFirst().orElse(null); + authenticationProviders.stream().filter(p-> p.getAuthenticationScope().getScope().equals(token.getAuthenticationScope().getScope())).findFirst().orElse(null); return new ServiceItem(provider, token.getUsername(), token.getPassword()); }).collect(Collectors.toList()); // Also need to add ServiceItems for providers not matched with a saved token, i.e. for logged-out services authenticationProviders.forEach(p -> { Optional serviceItem = serviceItems.stream().filter(si -> - p.getAuthenticationScope().equals(si.getAuthenticationScope())).findFirst(); + p.getAuthenticationScope().getScope().equals(si.getAuthenticationScope().getScope())).findFirst(); if(serviceItem.isEmpty()){ serviceItems.add(new ServiceItem(p)); } }); - serviceItems.sort(Comparator.comparing(ServiceItem::getAuthenticationScope)); + serviceItems.sort(Comparator.comparing(i -> i.getAuthenticationScope().getDisplayName())); Platform.runLater(() -> { this.serviceItems.setAll(serviceItems); listEmpty.set(savedTokens.isEmpty()); @@ -241,7 +251,13 @@ public AuthenticationScope getAuthenticationScope() { @SuppressWarnings("unused") public String getScope(){ return serviceAuthenticationProvider != null ? - serviceAuthenticationProvider.getAuthenticationScope().getName() : ""; + serviceAuthenticationProvider.getAuthenticationScope().getScope() : ""; + } + + @SuppressWarnings("unused") + public String getDisplayName(){ + return serviceAuthenticationProvider != null ? + serviceAuthenticationProvider.getAuthenticationScope().getDisplayName() : ""; } public String getPassword(){ @@ -260,7 +276,8 @@ public boolean isLoginAction(){ return loginAction; } } - private class UsernameTableCell extends TableCell{ + + private static class UsernameTableCell extends TableCell{ private final TextField textField = new TextField(); public UsernameTableCell(){ diff --git a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementStage.java b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementStage.java index ef51b00f04..42548efe60 100644 --- a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementStage.java +++ b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementStage.java @@ -61,7 +61,6 @@ public CredentialsManagementStage(List authentica try { fxmlLoader.load(); Scene scene = new Scene(fxmlLoader.getRoot()); - scene.getStylesheets().add(getClass().getResource("/css/credentials-management-style.css").toExternalForm()); setTitle(Messages.Title); setScene(scene); } catch (Exception exception) { diff --git a/app/credentials-management/src/main/resources/css/credentials-management-style.css b/app/credentials-management/src/main/resources/css/credentials-management-style.css index 5f318d1728..43ba9fc805 100644 --- a/app/credentials-management/src/main/resources/css/credentials-management-style.css +++ b/app/credentials-management/src/main/resources/css/credentials-management-style.css @@ -11,8 +11,12 @@ } .table-view .table-cell{ - -fx-font-weight: bold; - -fx-font-size: 14px; + -fx-font-size: 12px; +} + +.table-view .column-header > .label{ + -fx-alignment: CENTER-LEFT; + -fx-padding: 5px 3px 3px 3px; } .button-style{ diff --git a/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml b/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml index 3c78f63e53..27da380fa6 100644 --- a/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml +++ b/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml @@ -42,7 +42,7 @@ - + diff --git a/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogAuthenticationScope.java b/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogAuthenticationScope.java new file mode 100644 index 0000000000..224361e498 --- /dev/null +++ b/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogAuthenticationScope.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 European Spallation Source ERIC. + */ + +package org.phoebus.applications.logbook.authentication; + +import org.phoebus.security.tokens.AuthenticationScope; + +public class OlogAuthenticationScope implements AuthenticationScope { + + @Override + public String getScope() { + return "logbook"; + } + + @Override + public String getDisplayName() { + return "Logbook"; + } +} diff --git a/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogServiceAuthenticationProvider.java b/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogServiceAuthenticationProvider.java index 4332b5ebbd..08fa708a02 100644 --- a/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogServiceAuthenticationProvider.java +++ b/app/logbook/olog/client-es/src/main/java/org/phoebus/applications/logbook/authentication/OlogServiceAuthenticationProvider.java @@ -27,6 +27,12 @@ public class OlogServiceAuthenticationProvider implements ServiceAuthenticationProvider { + private final AuthenticationScope ologAuthenticationScope; + + public OlogServiceAuthenticationProvider(){ + ologAuthenticationScope = new OlogAuthenticationScope(); + } + @Override public void authenticate(String username, String password){ try { @@ -45,6 +51,6 @@ public void logout(String token) { @Override public AuthenticationScope getAuthenticationScope() { - return AuthenticationScope.LOGBOOK; + return ologAuthenticationScope; } } diff --git a/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogHttpClient.java b/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogHttpClient.java index 5a82c242e0..b99dc28ef9 100644 --- a/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogHttpClient.java +++ b/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogHttpClient.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.phoebus.applications.logbook.authentication.OlogAuthenticationScope; import org.phoebus.logbook.Attachment; import org.phoebus.logbook.LogClient; import org.phoebus.logbook.LogEntry; @@ -112,7 +113,7 @@ public OlogHttpClient build() { private ScopedAuthenticationToken getCredentialsFromSecureStore() { try { SecureStore secureStore = new SecureStore(); - return secureStore.getScopedAuthenticationToken(AuthenticationScope.LOGBOOK); + return secureStore.getScopedAuthenticationToken(new OlogAuthenticationScope()); } catch (Exception e) { Logger.getLogger(OlogHttpClient.class.getName()).log(Level.WARNING, "Unable to instantiate SecureStore", e); return null; diff --git a/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogAuthenticationScope.java b/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogAuthenticationScope.java new file mode 100644 index 0000000000..b773e4df34 --- /dev/null +++ b/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogAuthenticationScope.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2025 European Spallation Source ERIC. + */ + +package org.phoebus.olog.api; + +import org.phoebus.security.tokens.AuthenticationScope; + +public class OlogAuthenticationScope implements AuthenticationScope { + + @Override + public String getScope() { + return "logbook"; + } + + @Override + public String getDisplayName() { + return "Logbook"; + } +} diff --git a/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogClient.java b/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogClient.java index 6e5ad73660..4a135ebbf4 100644 --- a/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogClient.java +++ b/app/logbook/olog/client/src/main/java/org/phoebus/olog/api/OlogClient.java @@ -123,7 +123,7 @@ public OlogClientBuilder password(String password) { private ScopedAuthenticationToken getCredentialsFromSecureStore() { try { SecureStore secureStore = new SecureStore(); - return secureStore.getScopedAuthenticationToken(AuthenticationScope.LOGBOOK); + return secureStore.getScopedAuthenticationToken(new OlogAuthenticationScope()); } catch (Exception e) { Logger.getLogger(OlogClient.class.getName()).log(Level.WARNING, "Unable to instantiate SecureStore", e); return null; diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java index 1c288ef30d..961b0bc8eb 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java @@ -39,6 +39,7 @@ import javafx.util.Callback; import javafx.util.Duration; import javafx.util.StringConverter; +import org.phoebus.applications.logbook.authentication.OlogAuthenticationScope; import org.phoebus.framework.jobs.JobManager; import org.phoebus.logbook.LogClient; import org.phoebus.logbook.LogEntry; @@ -202,7 +203,7 @@ public void initialize() { contextMenu.setOnShowing(e -> { try { SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(AuthenticationScope.LOGBOOK); + ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(new OlogAuthenticationScope()); userHasSignedIn.set(scopedAuthenticationToken != null); } catch (Exception ex) { logger.log(Level.WARNING, "Secure Store file not found.", ex); diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java index a4ae21527c..8b01b0027a 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java @@ -62,6 +62,8 @@ import java.net.URL; import java.util.regex.Pattern; import java.util.regex.Matcher; + +import org.phoebus.applications.logbook.authentication.OlogAuthenticationScope; import org.phoebus.logbook.olog.ui.LogbookUIPreferences; import javafx.util.Callback; @@ -756,7 +758,7 @@ public void submit() { try { SecureStore store = new SecureStore(); ScopedAuthenticationToken scopedAuthenticationToken = - new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, usernameProperty.get(), passwordProperty.get()); + new ScopedAuthenticationToken(new OlogAuthenticationScope(), usernameProperty.get(), passwordProperty.get()); store.setScopedAuthentication(scopedAuthenticationToken); } catch (Exception ex) { logger.log(Level.WARNING, "Secure Store file not found.", ex); @@ -980,7 +982,7 @@ public void fetchStoredUserCredentials() { // Get the SecureStore. Retrieve username and password. try { SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(AuthenticationScope.LOGBOOK); + ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(new OlogAuthenticationScope()); // Could be accessed from JavaFX Application Thread when updating, so synchronize. synchronized (usernameProperty) { usernameProperty.set(scopedAuthenticationToken == null ? "" : scopedAuthenticationToken.getUsername()); diff --git a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationProvider.java b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationProvider.java index e23900c665..3dc30386a6 100644 --- a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationProvider.java +++ b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationProvider.java @@ -19,7 +19,6 @@ package org.phoebus.applications.saveandrestore.authentication; -import org.phoebus.applications.saveandrestore.Preferences; import org.phoebus.applications.saveandrestore.model.UserData; import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreService; import org.phoebus.security.authorization.ServiceAuthenticationProvider; @@ -33,6 +32,12 @@ */ public class SaveAndRestoreAuthenticationProvider implements ServiceAuthenticationProvider { + private final AuthenticationScope saveAndRestoreAuthenticationScope; + + public SaveAndRestoreAuthenticationProvider() { + saveAndRestoreAuthenticationScope = new SaveAndRestoreAuthenticationScope(); + } + @Override public void authenticate(String username, String password) { SaveAndRestoreService saveAndRestoreService = SaveAndRestoreService.getInstance(); @@ -56,7 +61,7 @@ public void logout(String token) { @Override public AuthenticationScope getAuthenticationScope() { - return AuthenticationScope.SAVE_AND_RESTORE; + return saveAndRestoreAuthenticationScope; } } diff --git a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationScope.java b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationScope.java new file mode 100644 index 0000000000..bbb87323ed --- /dev/null +++ b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/authentication/SaveAndRestoreAuthenticationScope.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2025 European Spallation Source ERIC. + */ + +package org.phoebus.applications.saveandrestore.authentication; + +import org.phoebus.security.tokens.AuthenticationScope; + +public class SaveAndRestoreAuthenticationScope implements AuthenticationScope { + @Override + public String getScope() { + return "save-and-restore"; + } + + @Override + public String getDisplayName() { + return "Save and Restore"; + } +} diff --git a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/client/SaveAndRestoreClientImpl.java b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/client/SaveAndRestoreClientImpl.java index 05c5755d8e..7aca71ace1 100644 --- a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/client/SaveAndRestoreClientImpl.java +++ b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/client/SaveAndRestoreClientImpl.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.phoebus.applications.saveandrestore.Messages; import org.phoebus.applications.saveandrestore.SaveAndRestoreClientException; +import org.phoebus.applications.saveandrestore.authentication.SaveAndRestoreAuthenticationScope; import org.phoebus.applications.saveandrestore.model.CompositeSnapshot; import org.phoebus.applications.saveandrestore.model.Configuration; import org.phoebus.applications.saveandrestore.model.ConfigurationData; @@ -80,7 +81,7 @@ public class SaveAndRestoreClientImpl implements SaveAndRestoreClient { private String getBasicAuthenticationHeader() { try { SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(AuthenticationScope.SAVE_AND_RESTORE); + ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(new SaveAndRestoreAuthenticationScope()); if (scopedAuthenticationToken != null) { String username = scopedAuthenticationToken.getUsername(); String password = scopedAuthenticationToken.getPassword(); diff --git a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/ContextMenuCreateSaveset.java b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/ContextMenuCreateSaveset.java index 01bbf79f53..19837adcbf 100644 --- a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/ContextMenuCreateSaveset.java +++ b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/ContextMenuCreateSaveset.java @@ -27,6 +27,7 @@ import javafx.stage.Stage; import org.phoebus.applications.saveandrestore.Messages; import org.phoebus.applications.saveandrestore.SaveAndRestoreApplication; +import org.phoebus.applications.saveandrestore.authentication.SaveAndRestoreAuthenticationScope; import org.phoebus.applications.saveandrestore.model.Node; import org.phoebus.applications.saveandrestore.model.NodeType; import org.phoebus.applications.saveandrestore.ui.configuration.ConfigurationFromSelectionController; @@ -34,7 +35,6 @@ import org.phoebus.framework.nls.NLS; import org.phoebus.framework.selection.Selection; import org.phoebus.security.store.SecureStore; -import org.phoebus.security.tokens.AuthenticationScope; import org.phoebus.security.tokens.ScopedAuthenticationToken; import org.phoebus.ui.javafx.ImageCache; import org.phoebus.ui.spi.ContextMenuEntry; @@ -90,11 +90,11 @@ public boolean isEnabled(){ try { SecureStore secureStore = new SecureStore(); ScopedAuthenticationToken token = - secureStore.getScopedAuthenticationToken(AuthenticationScope.SAVE_AND_RESTORE); + secureStore.getScopedAuthenticationToken(new SaveAndRestoreAuthenticationScope()); return token != null; } catch (Exception e) { Logger.getLogger(ContextMenuCreateSaveset.class.getName()).log(Level.WARNING, "Unable to retrieve authentication token for " + - AuthenticationScope.SAVE_AND_RESTORE.getName() + " scope", e); + new SaveAndRestoreAuthenticationScope().getScope() + " scope", e); return false; } } diff --git a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/SaveAndRestoreBaseController.java b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/SaveAndRestoreBaseController.java index 9b992cf579..e1e55911f0 100644 --- a/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/SaveAndRestoreBaseController.java +++ b/app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/SaveAndRestoreBaseController.java @@ -20,9 +20,9 @@ package org.phoebus.applications.saveandrestore.ui; import javafx.beans.property.SimpleStringProperty; +import org.phoebus.applications.saveandrestore.authentication.SaveAndRestoreAuthenticationScope; import org.phoebus.applications.saveandrestore.model.websocket.SaveAndRestoreWebSocketMessage; import org.phoebus.security.store.SecureStore; -import org.phoebus.security.tokens.AuthenticationScope; import org.phoebus.security.tokens.ScopedAuthenticationToken; import java.util.List; @@ -42,7 +42,7 @@ public SaveAndRestoreBaseController() { try { SecureStore secureStore = new SecureStore(); ScopedAuthenticationToken token = - secureStore.getScopedAuthenticationToken(AuthenticationScope.SAVE_AND_RESTORE); + secureStore.getScopedAuthenticationToken(new SaveAndRestoreAuthenticationScope()); if (token != null) { userIdentity.set(token.getUsername()); } else { @@ -50,14 +50,14 @@ public SaveAndRestoreBaseController() { } } catch (Exception e) { Logger.getLogger(SaveAndRestoreBaseController.class.getName()).log(Level.WARNING, "Unable to retrieve authentication token for " + - AuthenticationScope.SAVE_AND_RESTORE.getName() + " scope", e); + new SaveAndRestoreAuthenticationScope().getScope()+ " scope", e); } } public void secureStoreChanged(List validTokens) { Optional token = validTokens.stream() - .filter(t -> t.getAuthenticationScope().equals(AuthenticationScope.SAVE_AND_RESTORE)).findFirst(); + .filter(t -> t.getAuthenticationScope().getScope().equals(new SaveAndRestoreAuthenticationScope().getScope())).findFirst(); if (token.isPresent()) { userIdentity.set(token.get().getUsername()); } else { diff --git a/core/security/src/main/java/org/phoebus/security/store/SecureStore.java b/core/security/src/main/java/org/phoebus/security/store/SecureStore.java index d70029174d..33f4162af0 100644 --- a/core/security/src/main/java/org/phoebus/security/store/SecureStore.java +++ b/core/security/src/main/java/org/phoebus/security/store/SecureStore.java @@ -12,8 +12,10 @@ import java.util.ServiceLoader; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.phoebus.security.PhoebusSecurity; +import org.phoebus.security.authorization.ServiceAuthenticationProvider; import org.phoebus.security.tokens.AuthenticationScope; import org.phoebus.security.tokens.ScopedAuthenticationToken; @@ -99,13 +101,13 @@ public void delete(String tag) throws Exception{ public ScopedAuthenticationToken getScopedAuthenticationToken(AuthenticationScope scope) throws Exception{ String username; String password; - if(scope == null || scope.getName().trim().isEmpty()){ + if(scope == null || scope.getScope().trim().isEmpty()){ username = get(USERNAME_TAG); password = get(PASSWORD_TAG); } else{ - username = get(scope.getName().toLowerCase() + "." + USERNAME_TAG); - password = get(scope.getName().toLowerCase() + "." + PASSWORD_TAG); + username = get(scope.getScope().toLowerCase() + "." + USERNAME_TAG); + password = get(scope.getScope().toLowerCase() + "." + PASSWORD_TAG); } if(username == null || password == null){ return null; @@ -118,13 +120,13 @@ public ScopedAuthenticationToken getScopedAuthenticationToken(AuthenticationScop */ public void deleteScopedAuthenticationToken(AuthenticationScope scope) throws Exception{ LOGGER.log(Level.INFO, "Deleting authentication token for scope: " + scope); - if(scope == null || scope.getName().trim().isEmpty()){ + if(scope == null || scope.getScope().trim().isEmpty()){ delete(USERNAME_TAG); delete(PASSWORD_TAG); } else{ - delete(scope.getName() + "." + USERNAME_TAG); - delete(scope.getName() + "." + PASSWORD_TAG); + delete(scope.getScope() + "." + USERNAME_TAG); + delete(scope.getScope() + "." + PASSWORD_TAG); } notifyChangeListeners(); } @@ -151,13 +153,13 @@ public void setScopedAuthentication(ScopedAuthenticationToken scopedAuthenticati throw new RuntimeException("Username and password must both be non-null and non-empty"); } AuthenticationScope scope = scopedAuthenticationToken.getAuthenticationScope(); - if(scope == null || scope.getName().trim().isEmpty()){ + if(scope == null || scope.getScope().trim().isEmpty()){ set(USERNAME_TAG, username); set(PASSWORD_TAG, password); } else{ - set(scope.getName() + "." + USERNAME_TAG, username); - set(scope.getName() + "." + PASSWORD_TAG, password); + set(scope.getScope() + "." + USERNAME_TAG, username); + set(scope.getScope() + "." + PASSWORD_TAG, password); } notifyChangeListeners(); LOGGER.log(Level.INFO, "Storing scoped authentication token " + scopedAuthenticationToken); @@ -197,8 +199,8 @@ private List matchEntries(List aliases) throw String username; String password; AuthenticationScope scope = null; - // Non-scoped alias? - if(tokens.length == 1 && USERNAME_TAG.equals(tokens[0])){ + + if(tokens.length == 1 && USERNAME_TAG.equals(tokens[0])){ // Non-scoped alias // It is assumed that the secure store can contain zero or one entries named "username" or "password". // It is further assumed that these are "matching" items, i.e. they constitute a non-scoped authentication // token that was persisted at some point. @@ -206,9 +208,12 @@ private List matchEntries(List aliases) throw password = get(PASSWORD_TAG); } else{ - scope = AuthenticationScope.fromString(tokens[0]); - username = get(scope.getName() + "." + USERNAME_TAG); - password = get(scope.getName() + "." + PASSWORD_TAG); + scope = findAuthenticationScopeFromProviders(tokens[0]); + if(scope == null){ + throw new IllegalArgumentException("No authentication provider found matching scope \"" + tokens[0] + "\""); + } + username = get(tokens[0] + "." + USERNAME_TAG); + password = get(scope.getScope() + "." + PASSWORD_TAG); } // Add only if password was found. if(password != null){ @@ -218,6 +223,18 @@ private List matchEntries(List aliases) throw return allScopedAuthenticationTokens; } + private AuthenticationScope findAuthenticationScopeFromProviders(String key){ + List authenticationProviders = + ServiceLoader.load(ServiceAuthenticationProvider.class).stream().map(ServiceLoader.Provider::get) + .collect(Collectors.toList()); + for(ServiceAuthenticationProvider serviceAuthenticationProvider : authenticationProviders){ + if(serviceAuthenticationProvider.getAuthenticationScope().getScope().equals(key)){ + return serviceAuthenticationProvider.getAuthenticationScope(); + } + } + return null; + } + private void notifyChangeListeners(){ ServiceLoader changeHandlers = ServiceLoader.load(SecureStoreChangeHandler.class); changeHandlers.stream().forEach(c -> { diff --git a/core/security/src/main/java/org/phoebus/security/tokens/AuthenticationScope.java b/core/security/src/main/java/org/phoebus/security/tokens/AuthenticationScope.java index a91367ef8c..87685bfc74 100644 --- a/core/security/src/main/java/org/phoebus/security/tokens/AuthenticationScope.java +++ b/core/security/src/main/java/org/phoebus/security/tokens/AuthenticationScope.java @@ -19,42 +19,26 @@ package org.phoebus.security.tokens; -import java.util.Arrays; - /** - * Enum constants for authentication scopes used in dedicated use cases and applications. - * Restrictions on the name of an {@link AuthenticationScope} value: - *
    - *
  • Must match regexp [a-z-]*, i.e. lower case alphanumeric chars, except digits, plus hyphen (-)
  • - *
  • Must be unique among other enum names
  • - *
+ * Interface defining how to interact with {@link AuthenticationScope}s */ -public enum AuthenticationScope { - - LOGBOOK("logbook"), - SAVE_AND_RESTORE("save-and-restore"); - - private String name = null; - - private String supportedNamePattern = "[a-z-]*"; +public interface AuthenticationScope{ /** - * Internal use. - * @param name Valid name - * @throws IllegalArgumentException if the name does not match [a-z-]*. + * @return A string that must be unique between implementations and must match regular expression [a-z-]* */ - AuthenticationScope(String name) throws IllegalArgumentException{ - if(!name.matches(supportedNamePattern)){ - throw new IllegalArgumentException("Name " + name + " invalid"); - } - this.name = name; - } + String getScope(); - public String getName(){ - return name; - } + /** + * @return A string intended for whatever UI. + */ + String getDisplayName(); - public static AuthenticationScope fromString(String s){ - return Arrays.stream(values()).filter(a -> a.name.equals(s)).findFirst().orElse(null); + /** + * Utility... + * @return true if the scope name is valid. + */ + default boolean isScopeNameValid(){ + return getScope() != null && getScope().matches("[a-z-]*"); } } diff --git a/core/security/src/main/java/org/phoebus/security/tokens/ScopedAuthenticationToken.java b/core/security/src/main/java/org/phoebus/security/tokens/ScopedAuthenticationToken.java index c90b60ef2d..7b34d28107 100644 --- a/core/security/src/main/java/org/phoebus/security/tokens/ScopedAuthenticationToken.java +++ b/core/security/src/main/java/org/phoebus/security/tokens/ScopedAuthenticationToken.java @@ -46,7 +46,7 @@ public ScopedAuthenticationToken(String username, String password){ public ScopedAuthenticationToken(AuthenticationScope scope, String username, String password){ this(username, password); if(scope != null){ - if(scope.getName().trim().isEmpty()){ + if(scope.getScope().trim().isEmpty()){ this.scope = null; } else{ @@ -76,6 +76,6 @@ public int hashCode(){ @Override public String toString(){ - return "Scope: " + (scope != null ? scope.getName() : "") + ", username: " + getUsername(); + return "Scope: " + (scope != null ? scope.getScope() : "") + ", username: " + getUsername(); } } diff --git a/core/security/src/test/java/org/phoebus/security/authorization/tokens/ScopedAuthenticationTokenTest.java b/core/security/src/test/java/org/phoebus/security/authorization/tokens/ScopedAuthenticationTokenTest.java index c55a59de5c..5be88b2427 100644 --- a/core/security/src/test/java/org/phoebus/security/authorization/tokens/ScopedAuthenticationTokenTest.java +++ b/core/security/src/test/java/org/phoebus/security/authorization/tokens/ScopedAuthenticationTokenTest.java @@ -43,16 +43,24 @@ public void testScopedAuthenticationToken() { scopedAuthenticationToken = new ScopedAuthenticationToken(null, "username", "password"); assertNull(scopedAuthenticationToken.getAuthenticationScope()); - scopedAuthenticationToken = new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, "username", "password"); - assertEquals(AuthenticationScope.LOGBOOK, scopedAuthenticationToken.getAuthenticationScope()); } @Test public void testEqualsAndHashCode() { ScopedAuthenticationToken scopedAuthenticationToken1 = new ScopedAuthenticationToken("username", "password"); ScopedAuthenticationToken scopedAuthenticationToken2 = new ScopedAuthenticationToken("username", "somethingelse"); - ScopedAuthenticationToken scopedAuthenticationToken3 = new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, "username", "somethingelse"); - ScopedAuthenticationToken scopedAuthenticationToken4 = new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, "username1", "somethingelse"); + ScopedAuthenticationToken scopedAuthenticationToken3 = new ScopedAuthenticationToken(new AuthenticationScope() { + @Override + public String getScope() { + return "key"; + } + + @Override + public String getDisplayName() { + return ""; + } + }, "username", "somethingelse"); + ScopedAuthenticationToken scopedAuthenticationToken4 = new ScopedAuthenticationToken(new TestAuthenticationScope(), "username1", "somethingelse"); assertEquals(scopedAuthenticationToken1, scopedAuthenticationToken2); assertNotEquals(scopedAuthenticationToken1, scopedAuthenticationToken3); @@ -66,8 +74,16 @@ public void testEqualsAndHashCode() { assertNotEquals(scopedAuthenticationToken1.hashCode(), scopedAuthenticationToken2.hashCode()); } - @Test - public void testFromString(){ - assertEquals(AuthenticationScope.SAVE_AND_RESTORE, AuthenticationScope.fromString(AuthenticationScope.SAVE_AND_RESTORE.getName())); + + private class TestAuthenticationScope implements AuthenticationScope{ + @Override + public String getScope(){ + return "key"; + } + + @Override + public String getDisplayName(){ + return "Display name"; + } } } diff --git a/core/ui/src/main/resources/css/credentials-management-style.css b/core/ui/src/main/resources/css/credentials-management-style.css deleted file mode 100644 index 5f318d1728..0000000000 --- a/core/ui/src/main/resources/css/credentials-management-style.css +++ /dev/null @@ -1,20 +0,0 @@ -.text-field-styling{ - -fx-padding: 5px 3px 3px 3px; - -fx-border-insets: 5px 3px 3px 3px; - -fx-background-insets: 5px 3px 3px 3px; - -fx-border-color: #cdcdcd; - -fx-border-radius: 3px; -} - -.table-view .table-column{ - -fx-alignment:center; -} - -.table-view .table-cell{ - -fx-font-weight: bold; - -fx-font-size: 14px; -} - -.button-style{ - -fx-pref-width: 100px; -} From 7be1d166ecfe4e3b353f1d8707261c555594c49b Mon Sep 17 00:00:00 2001 From: georgweiss Date: Fri, 12 Sep 2025 15:12:31 +0200 Subject: [PATCH 02/11] UI updates to credentials management --- .../src/main/resources/css/login-to-all.css | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/credentials-management/src/main/resources/css/login-to-all.css diff --git a/app/credentials-management/src/main/resources/css/login-to-all.css b/app/credentials-management/src/main/resources/css/login-to-all.css new file mode 100644 index 0000000000..9c912b251a --- /dev/null +++ b/app/credentials-management/src/main/resources/css/login-to-all.css @@ -0,0 +1,3 @@ +.table-view .table-cell{ + -fx-background-color: #e5f5e0; +} \ No newline at end of file From ce66c6d20c65313e59d25cfe7885172d2652474f Mon Sep 17 00:00:00 2001 From: georgweiss Date: Tue, 16 Sep 2025 13:12:59 +0200 Subject: [PATCH 03/11] Update credentials dialog UI --- .../CredentialsManagementController.java | 124 ++++++++++++------ .../css/credentials-management-style.css | 12 +- .../CredentialsManagement.fxml | 17 ++- .../credentialsmanagement/messages.properties | 7 +- 4 files changed, 104 insertions(+), 56 deletions(-) diff --git a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java index 03ef1d148d..e15e3efb6b 100644 --- a/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java +++ b/app/credentials-management/src/main/java/org/phoebus/applications/credentialsmanagement/CredentialsManagementController.java @@ -19,7 +19,10 @@ package org.phoebus.applications.credentialsmanagement; import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -62,7 +65,7 @@ public class CredentialsManagementController { private TableView tableView; @SuppressWarnings("unused") @FXML - private TableColumn actionButtonColumn; + private TableColumn actionButtonColumn; @SuppressWarnings("unused") @FXML private TableColumn usernameColumn; @@ -71,7 +74,16 @@ public class CredentialsManagementController { private TableColumn passwordColumn; @SuppressWarnings("unused") @FXML - private Button clearAllCredentialsButton; + private Button loginToAllButton; + @SuppressWarnings("unused") + @FXML + private Button logoutFromAllButton; + @SuppressWarnings("unused") + @FXML + private TextField loginToAllUsernameTextField; + @SuppressWarnings("unused") + @FXML + private PasswordField loginToAllPasswordTextField; @SuppressWarnings("unused") @FXML private TableColumn scopeColumn; @@ -82,6 +94,8 @@ public class CredentialsManagementController { private final SecureStore secureStore; private static final Logger LOGGER = Logger.getLogger(CredentialsManagementController.class.getName()); private final List authenticationProviders; + private final StringProperty loginToAllUsernameProperty = new SimpleStringProperty(); + private final StringProperty loginToAllPasswordProperty = new SimpleStringProperty(); private Stage stage; @@ -95,33 +109,34 @@ public CredentialsManagementController(List authe public void initialize() { tableView.getStylesheets().add(getClass().getResource("/css/credentials-management-style.css").toExternalForm()); - clearAllCredentialsButton.disableProperty().bind(listEmpty); - Callback, TableCell> actionColumnCellFactory = new Callback<>() { + + logoutFromAllButton.disableProperty().bind(listEmpty); + Callback, TableCell> actionColumnCellFactory = new Callback<>() { @Override - public TableCell call(final TableColumn param) { - final TableCell cell = new TableCell<>() { + public TableCell call(final TableColumn param) { + final TableCell cell = new TableCell<>() { private final Button btn = new Button(Messages.LogoutButtonText); + { btn.getStyleClass().add("button-style"); btn.setOnAction((ActionEvent event) -> { ServiceItem serviceItem = getTableView().getItems().get(getIndex()); - if(serviceItem.isLoginAction()){ + if (serviceItem.loginAction) { login(serviceItem); - } - else{ + } else { logOut(serviceItem.getAuthenticationScope()); } }); } @Override - public void updateItem(Void o, boolean empty) { + public void updateItem(ServiceItem o, boolean empty) { super.updateItem(o, empty); if (empty) { setGraphic(null); } else { - if(getTableRow() != null && getTableRow().getItem() != null){ + if (getTableRow() != null && getTableRow().getItem() != null) { btn.setText(getTableRow().getItem().loginAction ? Messages.LoginButtonText : Messages.LogoutButtonText); } @@ -136,14 +151,37 @@ public void updateItem(Void o, boolean empty) { usernameColumn.setCellFactory(c -> new UsernameTableCell()); passwordColumn.setCellFactory(c -> new PasswordTableCell()); - scopeColumn.setStyle( "-fx-alignment: CENTER-LEFT;"); + loginToAllUsernameTextField.textProperty().bindBidirectional(loginToAllUsernameProperty); + loginToAllPasswordTextField.textProperty().bindBidirectional(loginToAllPasswordProperty); + + loginToAllButton.disableProperty().bind(Bindings.createBooleanBinding(() -> loginToAllUsernameProperty.get() == null || + loginToAllUsernameProperty.get().isEmpty() || + loginToAllPasswordProperty.get() == null || + loginToAllPasswordProperty.get().isEmpty(), + loginToAllUsernameProperty, loginToAllPasswordProperty)); updateTable(); + + // Don't want focus on the username field for "login to all" as that obscures the prompt. + // Let table request focus. + Platform.runLater(() -> tableView.requestFocus()); + } + + @SuppressWarnings("unused") + @FXML + public void logoutFromAll() { + try { + secureStore.deleteAllScopedAuthenticationTokens(); + updateTable(); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Failed to delete all authentication tokens from key store", e); + ExceptionDetailsErrorDialog.openError(parent, Messages.ErrorDialogTitle, Messages.ErrorDialogBody, e); + } } @SuppressWarnings("unused") @FXML - public void logOutFromAll() { + public void loginToAll() { try { secureStore.deleteAllScopedAuthenticationTokens(); updateTable(); @@ -156,9 +194,10 @@ public void logOutFromAll() { /** * Attempts to sign in user based on provided credentials. If sign-in succeeds, this method will close the * associated UI. + * * @param serviceItem The {@link ServiceItem} defining the scope, and implicitly the authentication service. */ - private void login(ServiceItem serviceItem){ + private void login(ServiceItem serviceItem) { try { serviceItem.getServiceAuthenticationProvider().authenticate(serviceItem.getUsername(), serviceItem.getPassword()); try { @@ -191,7 +230,7 @@ private void updateTable() { // Match saved tokens with an authentication provider, where applicable List serviceItems = savedTokens.stream().map(token -> { ServiceAuthenticationProvider provider = - authenticationProviders.stream().filter(p-> p.getAuthenticationScope().getScope().equals(token.getAuthenticationScope().getScope())).findFirst().orElse(null); + authenticationProviders.stream().filter(p -> p.getAuthenticationScope().getScope().equals(token.getAuthenticationScope().getScope())).findFirst().orElse(null); return new ServiceItem(provider, token.getUsername(), token.getPassword()); }).collect(Collectors.toList()); // Also need to add ServiceItems for providers not matched with a saved token, i.e. for logged-out services @@ -199,11 +238,12 @@ private void updateTable() { Optional serviceItem = serviceItems.stream().filter(si -> p.getAuthenticationScope().getScope().equals(si.getAuthenticationScope().getScope())).findFirst(); - if(serviceItem.isEmpty()){ + if (serviceItem.isEmpty()) { serviceItems.add(new ServiceItem(p)); } }); serviceItems.sort(Comparator.comparing(i -> i.getAuthenticationScope().getDisplayName())); + Platform.runLater(() -> { this.serviceItems.setAll(serviceItems); listEmpty.set(savedTokens.isEmpty()); @@ -219,7 +259,7 @@ public static class ServiceItem { private final ServiceAuthenticationProvider serviceAuthenticationProvider; private String username; private String password; - private boolean loginAction = false; + private boolean loginAction; public ServiceItem(ServiceAuthenticationProvider serviceAuthenticationProvider, String username, String password) { this.serviceAuthenticationProvider = serviceAuthenticationProvider; @@ -229,14 +269,14 @@ public ServiceItem(ServiceAuthenticationProvider serviceAuthenticationProvider, public ServiceItem(ServiceAuthenticationProvider serviceAuthenticationProvider) { this.serviceAuthenticationProvider = serviceAuthenticationProvider; - loginAction = true; + this.loginAction = true; } public String getUsername() { return username; } - public void setUsername(String username){ + public void setUsername(String username) { this.username = username; } @@ -249,53 +289,54 @@ public AuthenticationScope getAuthenticationScope() { * @return String representation of the authentication scope. */ @SuppressWarnings("unused") - public String getScope(){ + public String getScope() { return serviceAuthenticationProvider != null ? serviceAuthenticationProvider.getAuthenticationScope().getScope() : ""; } @SuppressWarnings("unused") - public String getDisplayName(){ + public String getDisplayName() { return serviceAuthenticationProvider != null ? serviceAuthenticationProvider.getAuthenticationScope().getDisplayName() : ""; } - public String getPassword(){ + public String getPassword() { return password; } - public void setPassword(String password){ + public void setPassword(String password) { this.password = password; + } public ServiceAuthenticationProvider getServiceAuthenticationProvider() { return serviceAuthenticationProvider; } - public boolean isLoginAction(){ + public boolean getLoginAction() { return loginAction; } } - private static class UsernameTableCell extends TableCell{ + private static class UsernameTableCell extends TableCell { private final TextField textField = new TextField(); - public UsernameTableCell(){ + public UsernameTableCell() { textField.getStyleClass().add("text-field-styling"); // Update model on key up - textField.setOnKeyReleased(ke -> getTableRow().getItem().setUsername(textField.getText())); + textField.setOnKeyReleased(ke -> { + getTableRow().getItem().setUsername(textField.getText()); + }); } @Override - protected void updateItem(String item, final boolean empty) - { + protected void updateItem(String item, final boolean empty) { super.updateItem(item, empty); - if(empty){ + if (empty) { setGraphic(null); - } - else{ + } else { textField.setText(item); - if(getTableRow() != null && getTableRow().getItem() != null){ + if (getTableRow() != null && getTableRow().getItem() != null) { // Disable field if user is logged in. textField.disableProperty().set(!getTableRow().getItem().loginAction); } @@ -304,25 +345,24 @@ protected void updateItem(String item, final boolean empty) } } - private class PasswordTableCell extends TableCell{ + private class PasswordTableCell extends TableCell { private final PasswordField passwordField = new PasswordField(); - public PasswordTableCell(){ + public PasswordTableCell() { passwordField.getStyleClass().add("text-field-styling"); // Update model on key up passwordField.setOnKeyReleased(ke -> getTableRow().getItem().setPassword(passwordField.getText())); } @Override - protected void updateItem(String item, final boolean empty) - { + protected void updateItem(String item, final boolean empty) { super.updateItem(item, empty); - if(empty){ + if (empty) { setGraphic(null); - } - else{ + } else { passwordField.setText(item == null ? item : "dummypass"); // Hack to not reveal password length - if(getTableRow() != null && getTableRow().getItem() != null) { + + if (getTableRow() != null && getTableRow().getItem() != null) { // Disable field if user is logged in. passwordField.disableProperty().set(!getTableRow().getItem().loginAction); } @@ -336,7 +376,7 @@ protected void updateItem(String item, final boolean empty) } } - public void setStage(Stage stage){ + public void setStage(Stage stage) { this.stage = stage; } } diff --git a/app/credentials-management/src/main/resources/css/credentials-management-style.css b/app/credentials-management/src/main/resources/css/credentials-management-style.css index 43ba9fc805..5e90f8aafc 100644 --- a/app/credentials-management/src/main/resources/css/credentials-management-style.css +++ b/app/credentials-management/src/main/resources/css/credentials-management-style.css @@ -1,24 +1,32 @@ .text-field-styling{ -fx-padding: 5px 3px 3px 3px; - -fx-border-insets: 5px 3px 3px 3px; + -fx-border-insets: 5px 3px 3px 2px; -fx-background-insets: 5px 3px 3px 3px; -fx-border-color: #cdcdcd; -fx-border-radius: 3px; } .table-view .table-column{ - -fx-alignment:center; + -fx-alignment:CENTER; +} + +.table-view { + -fx-table-cell-border-color: transparent; } .table-view .table-cell{ -fx-font-size: 12px; + -fx-background-color: #FFFFFF; } .table-view .column-header > .label{ -fx-alignment: CENTER-LEFT; + -fx-font-size: 14px; -fx-padding: 5px 3px 3px 3px; } .button-style{ -fx-pref-width: 100px; } + + diff --git a/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml b/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml index 27da380fa6..a6d130853c 100644 --- a/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml +++ b/app/credentials-management/src/main/resources/org/phoebus/applications/credentialsmanagement/CredentialsManagement.fxml @@ -22,30 +22,29 @@ - + - + + +