Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
9384419
Save&restore service: added authentication for non-GET requests
georgweiss Aug 23, 2023
300083a
Save&restore client side authentication setup
georgweiss Aug 23, 2023
584b9fa
Save&restore authentication, client side
georgweiss Aug 24, 2023
224e0c3
Merge branch 'master' into CSSTUDIO-1684
georgweiss Aug 30, 2023
8620236
Save&restore authentication mandatory for all except GET. Demo scheme…
georgweiss Aug 30, 2023
91bdf07
Save&restore service: user id from Principal
georgweiss Aug 31, 2023
a606b3b
Client side of save&restore authentication
georgweiss Aug 31, 2023
12270de
Save&restore context menu items disabled based on user authentication…
georgweiss Sep 4, 2023
b0e5e3b
Bug fix snapshot comparison logic
georgweiss Sep 5, 2023
f685da1
Merge branch 'master' into CSSTUDIO-1684
georgweiss Sep 11, 2023
4060b93
Updates after merge with master
georgweiss Sep 11, 2023
9235222
Added missing javadoc
georgweiss Sep 11, 2023
2f252f4
Resolve merge conflicts
georgweiss Sep 12, 2023
800e60a
Save&restore handler for secure store changes
georgweiss Sep 12, 2023
20714f4
Remove Edit context menu item for save&restore configurations
georgweiss Sep 12, 2023
bb01cf8
Save&restore: configuration UI elements enabled only if user is authe…
georgweiss Sep 12, 2023
a44ec35
Disable create/add context menu entry for save&restore configurations…
georgweiss Sep 12, 2023
f29d68c
Save&restore: snapshot UI elements enabled only if user is authenticated
georgweiss Sep 13, 2023
1e7bf0b
Save&restore: composite snapshot UI elements enabled only if user is …
georgweiss Sep 13, 2023
39cf917
Save&restore: disable drag-n-drop if user is not authenticated
georgweiss Sep 13, 2023
c9f1932
Save&restore: filter&search view UI elements disabled if user not aut…
georgweiss Sep 13, 2023
5f12954
Save&restore: move information on authenticated user
georgweiss Sep 13, 2023
e4dd5b4
Resolve merge conflict
georgweiss Sep 14, 2023
1e504f2
Save&restore: clean-up in cell renderer and context menus
georgweiss Sep 14, 2023
b706e0c
Removed unused UI elements
georgweiss Sep 14, 2023
a313490
Updated documentation due to authentication in save&restore
georgweiss Sep 14, 2023
2cfa772
Renamed a few settings/variables to make more sense
georgweiss Sep 25, 2023
e33d9a8
Merge branch 'master' into CSSTUDIO-1684
georgweiss Oct 10, 2023
7854d68
Documentation for save&restore authorization
georgweiss Oct 10, 2023
affe1ab
Updating NodeControllerTest due to authorization
georgweiss Oct 11, 2023
807b613
Authorization set for creating and updating configurations
georgweiss Oct 12, 2023
c7dd2c8
Authorization for saving and updating snapshots
georgweiss Oct 12, 2023
206af33
Authorization for composite snapshots
georgweiss Oct 12, 2023
fbe19d2
Authorization for save&restore filters
georgweiss Oct 13, 2023
8406c85
Clarifications in docs about save&restore authorization details
georgweiss Oct 13, 2023
57d53ef
Save&restore delete operation must check if all nodes selected by use…
georgweiss Oct 13, 2023
b81169a
Minor bug fixes in save&restore tree view tool tip
georgweiss Oct 16, 2023
247dd27
Fix failing unit test
georgweiss Oct 20, 2023
e329987
Fixing additional build issues
georgweiss Oct 21, 2023
1e80132
Fix merge conflict
georgweiss Oct 27, 2023
3af4817
Testing different authorization config for save&restore
georgweiss Oct 27, 2023
fa14440
Merge branch 'master' into CSSTUDIO-1684
georgweiss Nov 3, 2023
4838091
Merge branch 'master' into CSSTUDIO-1684
georgweiss Nov 8, 2023
4043522
Making save&restore authorization/authentication optional
georgweiss Nov 8, 2023
1a6c789
Authentication/authorization for save&restore tag management
georgweiss Nov 8, 2023
db12971
Remaining pieces for save&restore authentication/authorization: filters
georgweiss Nov 9, 2023
ebc41df
Merge branch 'master' into CSSTUDIO-1684
georgweiss Nov 12, 2023
6b594b1
Updated authorization strategy: authentication mandatory, authorizati…
georgweiss Nov 13, 2023
9b626bf
Final pieces of the save&restore AA
georgweiss Nov 14, 2023
b3178f1
Including active directory Authentication manager
shroffk Nov 14, 2023
44ebd82
Add authority mapper to convert to ROLE_XXX
shroffk Nov 14, 2023
dd349b6
Merge pull request #2870 from ControlSystemStudio/save_restore_ks
shroffk Nov 14, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public String getDisplayName() {
@Override
public AppInstance create() {
List<ServiceAuthenticationProvider> authenticationProviders =
ServiceLoader.load(ServiceAuthenticationProvider.class).stream().map(Provider::get).collect(Collectors.toList());
ServiceLoader.load(ServiceAuthenticationProvider.class).stream().map(Provider::get)
.collect(Collectors.toList());
try {
SecureStore secureStore = new SecureStore();
new CredentialsManagementStage(authenticationProviders, secureStore).show();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;
import javafx.util.Callback;
import org.phoebus.framework.jobs.JobManager;
import org.phoebus.security.authorization.ServiceAuthenticationProvider;
Expand Down Expand Up @@ -75,6 +77,8 @@ public class CredentialsManagementController {
private static final Logger LOGGER = Logger.getLogger(CredentialsManagementController.class.getName());
private final List<ServiceAuthenticationProvider> authenticationProviders;

private Stage stage;

public CredentialsManagementController(List<ServiceAuthenticationProvider> authenticationProviders, SecureStore secureStore) {
this.authenticationProviders = authenticationProviders;
this.secureStore = secureStore;
Expand Down Expand Up @@ -139,18 +143,22 @@ 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){
try {
serviceItem.getServiceAuthenticationProvider().authenticate(serviceItem.getUsername(), serviceItem.getPassword());
try {
secureStore.setScopedAuthentication(new ScopedAuthenticationToken(serviceItem.getAuthenticationScope(),
serviceItem.getUsername(),
serviceItem.getPassword()));
stage.close();
} catch (Exception exception) {
LOGGER.log(Level.WARNING, "Failed to store credentials", exception);
}
updateTable();

} catch (Exception exception) {
LOGGER.log(Level.WARNING, "Failed to login to service", exception);
ExceptionDetailsErrorDialog.openError(parent, "Login Failure", "Failed to login to service", exception);
Expand Down Expand Up @@ -252,7 +260,7 @@ public boolean isLoginAction(){
return loginAction;
}
}
private static class UsernameTableCell extends TableCell<ServiceItem, String>{
private class UsernameTableCell extends TableCell<ServiceItem, String>{
private final TextField textField = new TextField();

public UsernameTableCell(){
Expand All @@ -279,7 +287,7 @@ protected void updateItem(String item, final boolean empty)
}
}

private static class PasswordTableCell extends TableCell<ServiceItem, String>{
private class PasswordTableCell extends TableCell<ServiceItem, String>{
private final PasswordField passwordField = new PasswordField();

public PasswordTableCell(){
Expand All @@ -301,8 +309,17 @@ protected void updateItem(String item, final boolean empty)
// Disable field if user is logged in.
passwordField.disableProperty().set(!getTableRow().getItem().loginAction);
}
passwordField.setOnKeyPressed(keyEvent -> {
if (keyEvent.getCode() == KeyCode.ENTER) {
CredentialsManagementController.this.login(getTableRow().getItem());
}
});
setGraphic(passwordField);
}
}
}

public void setStage(Stage stage){
this.stage = stage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public CredentialsManagementStage(List<ServiceAuthenticationProvider> authentica
CredentialsManagementController controller =
(CredentialsManagementController) clazz.getConstructor(List.class, SecureStore.class)
.newInstance(authenticationProviders, secureStore);
controller.setStage(this);
return controller;

} catch (Exception e) {
Expand Down
25 changes: 23 additions & 2 deletions app/save-and-restore/app/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ The application uses the save-and-restore service deployed on the network such t
HTTP(s). The URL of the service is specified in the save-and-restore.properties file, or in the settings file
pointed to on the command line.

Actions that create, modify or delete data are protected by the service. User must sign in through the
Crendentials Manager application. See also below.

Nodes and node types
--------------------

Expand Down Expand Up @@ -392,7 +395,25 @@ The items of this context menu offers actions associated with a PV, which is sim
other applications. However, user should be aware that the "Data Browser" item will launch the Data Browser app for
the selected PV *around the point in time defined by the PV timestamp*.



Authentication and Authorization
--------------------------------

Authorization uses a role-based approach like so:

* Unauthenticated users may read data, i.e. browse the tree and view configurations, snapshots, search and view filters.
* Role "user":
* Create and save configurations
* Create and save snapshots
* Create and save composite snapshots
* Create and save filters
* Update and delete objects if user name matches object's user id and:
* Object is a snapshot and not referenced in a composite snapshot node
* Object is a composite snapshot node
* Object is configuration or folder node with no child nodes
* Object is a filter
* Role "superuser": +perform restore operation
* Role "admin": no restrictions

Roles are defined and managed on the service. Role (group) membership is managed in Active Directory or LDAP.


Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class Messages {

public static String alertContinue;
public static String alertAddingPVsToConfiguration;
public static String authenticationFailed;
public static String baseSetpoint;
public static String buttonSearch;
public static String cannotCompareHeader;
Expand Down Expand Up @@ -69,9 +70,11 @@ public class Messages {
public static String duplicatePVNamesFoundInSelection;
public static String editFilter;
public static String errorActionFailed;
public static String errorAddTagFailed;
public static String errorCreateFolderFailed;
public static String errorCreateConfigurationFailed;
public static String errorDeleteNodeFailed;
public static String errorDeleteTagFailed;
public static String errorGeneric;
public static String errorUnableToRetrieveData;
public static String exportConfigurationLabel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public class SaveAndRestoreApplication implements AppResourceDescriptor {
public static final String NAME = "saveandrestore";
public static final String DISPLAY_NAME = "Save And Restore";

private AppInstance instance;

/**
* Custom MIME type definition for the purpose of drag-n-drop in the
*/
Expand Down Expand Up @@ -71,12 +73,18 @@ public AppInstance create(URI uri) {
if(uri != null){
((SaveAndRestoreInstance)tab.getApplication()).openResource(uri);
}
return tab.getApplication();
instance = tab.getApplication();
return instance;
}
}
}
}

return new SaveAndRestoreInstance(this, uri);
instance = new SaveAndRestoreInstance(this, uri);
return instance;
}

public AppInstance getInstance(){
return instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@
import org.phoebus.framework.persistence.Memento;
import org.phoebus.framework.spi.AppDescriptor;
import org.phoebus.framework.spi.AppInstance;
import org.phoebus.security.tokens.ScopedAuthenticationToken;
import org.phoebus.ui.docking.DockItem;
import org.phoebus.ui.docking.DockPane;

import java.net.URI;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SaveAndRestoreInstance implements AppInstance {

private final AppDescriptor appDescriptor;
private SaveAndRestoreController controller;
private final SaveAndRestoreController saveAndRestoreController;

public SaveAndRestoreInstance(AppDescriptor appDescriptor, URI uri) {
this.appDescriptor = appDescriptor;
Expand All @@ -62,9 +64,9 @@ public SaveAndRestoreInstance(AppDescriptor appDescriptor, URI uri) {
Logger.getLogger(SaveAndRestoreApplication.class.getName()).log(Level.SEVERE, "Failed loading fxml", e);
}

controller = loader.getController();
saveAndRestoreController = loader.getController();

tab.setOnCloseRequest(event -> controller.handleTabClosed());
tab.setOnCloseRequest(event -> saveAndRestoreController.handleTabClosed());

DockPane.getActiveDockPane().addTab(tab);
}
Expand All @@ -76,10 +78,14 @@ public AppDescriptor getAppDescriptor() {

@Override
public void save(Memento memento) {
controller.saveLocalState();
saveAndRestoreController.saveLocalState();
}

public void openResource(URI uri) {
controller.openResource(uri);
saveAndRestoreController.openResource(uri);
}

public void secureStoreChanged(List<ScopedAuthenticationToken> validTokens){
saveAndRestoreController.secureStoreChanged(validTokens);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/

package org.phoebus.applications.saveandrestore.authentication;

import org.phoebus.applications.saveandrestore.Preferences;
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreService;
import org.phoebus.security.authorization.ServiceAuthenticationProvider;
import org.phoebus.security.tokens.AuthenticationScope;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Authentication provider for the save-and-restore service.
*/
public class SaveAndRestoreAuthenticationProvider implements ServiceAuthenticationProvider {

@Override
public void authenticate(String username, String password){
SaveAndRestoreService saveAndRestoreService = SaveAndRestoreService.getInstance();
try {
saveAndRestoreService.authenticate(username, password);
} catch (Exception e) {
Logger.getLogger(SaveAndRestoreAuthenticationProvider.class.getName())
.log(Level.WARNING, "Failed to authenticate user " + username + " against save&restore service", e);
throw new RuntimeException(e);
}
}

@Override
public void logout(String token) {
// Not implemented for save&restore
}

@Override
public AuthenticationScope getAuthenticationScope(){
return AuthenticationScope.SAVE_AND_RESTORE;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2020 European Spallation Source ERIC.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/

package org.phoebus.applications.saveandrestore.authentication;

import org.phoebus.applications.saveandrestore.SaveAndRestoreApplication;
import org.phoebus.applications.saveandrestore.SaveAndRestoreInstance;
import org.phoebus.framework.spi.AppDescriptor;
import org.phoebus.framework.workbench.ApplicationService;
import org.phoebus.security.store.SecureStoreChangeHandler;
import org.phoebus.security.tokens.ScopedAuthenticationToken;

import java.util.List;

public class SecureStoreChangeHandlerImpl implements SecureStoreChangeHandler {

/**
* Callback method implementation.
*
* @param validTokens A list of valid {@link ScopedAuthenticationToken}s, i.e. a list of tokens associated
* with scopes where is authenticated.
*/
@Override
public void secureStoreChanged(List<ScopedAuthenticationToken> validTokens) {
AppDescriptor appDescriptor = ApplicationService.findApplication(SaveAndRestoreApplication.NAME);
if (appDescriptor != null && appDescriptor instanceof SaveAndRestoreApplication) {
SaveAndRestoreApplication saveAndRestoreApplication = (SaveAndRestoreApplication) appDescriptor;
SaveAndRestoreInstance saveAndRestoreInstance = (SaveAndRestoreInstance) saveAndRestoreApplication.getInstance();
saveAndRestoreInstance.secureStoreChanged(validTokens);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ public interface SaveAndRestoreClient {
*/
Node updateNode(Node nodeToUpdate, boolean customTimeForMigration);

void deleteNode(String uniqueNodeId);

/**
* Deletes a list of {@link Node}s
*
Expand Down Expand Up @@ -138,14 +136,24 @@ public interface SaveAndRestoreClient {

ConfigurationData getConfigurationData(String nodeId);

/**
* Creates a new {@link Node} of type {@link NodeType#CONFIGURATION} in the remote
* service.
* @param parentNodeId Non-null and non-empty unique id of an existing parent {@link Node},
* which must be of type {@link NodeType#FOLDER}.
* @param configuration {@link ConfigurationData} object
* @return A representation of the persisted {@link Configuration}.
*/
Configuration createConfiguration(String parentNodeId, Configuration configuration);

Configuration updateConfiguration(Configuration configuration);


SnapshotData getSnapshotData(String uniqueId);

Snapshot saveSnapshot(String parentNodeId, Snapshot snapshot);
Snapshot createSnapshot(String parentNodeId, Snapshot snapshot);

Snapshot updateSnapshot(Snapshot snapshot);

/**
* Creates a new {@link CompositeSnapshot}.
Expand Down Expand Up @@ -214,4 +222,13 @@ public interface SaveAndRestoreClient {
* passed in the <code>tagData</code> parameter.
*/
List<Node> deleteTag(TagData tagData);

/**
* For the purpose of login and authentication in the service.
* @param userName User's account name
* @param password User's password
* @return A {@link UserData} object if login is successful, otherwise implementation should throw
* an exception.
*/
UserData authenticate(String userName, String password);
}
Loading