Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.openaz.xacml.admin.components; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collection; import java.util.Iterator; import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.PushResult; import org.vaadin.dialogs.ConfirmDialog; import org.vaadin.dialogs.ConfirmDialog.ContentMode; import org.apache.openaz.xacml.admin.XacmlAdminAuthorization; import org.apache.openaz.xacml.admin.XacmlAdminUI; import org.apache.openaz.xacml.admin.model.GitRepositoryContainer; import org.apache.openaz.xacml.admin.util.AdminNotification; import org.apache.openaz.xacml.admin.util.OnDemandFileDownloader; import org.apache.openaz.xacml.admin.util.OnDemandFileDownloader.OnDemandStreamResource; import org.apache.openaz.xacml.admin.util.XACMLPolicyImporter; import org.apache.openaz.xacml.admin.view.windows.GitPushWindow; import org.apache.openaz.xacml.admin.view.windows.GitSynchronizeWindow; import org.apache.openaz.xacml.admin.view.windows.PolicyNameEditorWindow; import org.apache.openaz.xacml.admin.view.windows.PolicyUploadWindow; import org.apache.openaz.xacml.admin.view.windows.RenamePolicyFileWindow; import org.apache.openaz.xacml.admin.view.windows.SubDomainEditorWindow; import org.apache.openaz.xacml.std.pap.StdPDPPolicy; import org.apache.openaz.xacml.util.XACMLPolicyScanner; import org.apache.openaz.xacml.util.XACMLPolicyScanner.CallbackResult; import org.apache.openaz.xacml.util.XACMLPolicyWriter; import com.vaadin.annotations.AutoGenerated; import com.vaadin.data.Item; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Notification; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.CloseHandler; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.Table.TableDragMode; import com.vaadin.ui.Table.TableTransferable; import com.vaadin.ui.TreeTable; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window.CloseEvent; import com.vaadin.ui.Window.CloseListener; /** * The class represents Policy Editor in Policy Authoring Tool */ public class PolicyWorkspace extends CustomComponent implements DropHandler, OnDemandStreamResource { /*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */ @AutoGenerated private VerticalLayout mainLayout; @AutoGenerated private HorizontalSplitPanel horizontalSplitPanel; @AutoGenerated private VerticalLayout verticalLayoutRightPanel; @AutoGenerated private TabSheet tabSheet; @AutoGenerated private HorizontalLayout horizontalLayoutRightToolbar; @AutoGenerated private Button buttonRight; @AutoGenerated private VerticalLayout verticalLayoutLeftPanel; @AutoGenerated private TreeTable treeWorkspace; @AutoGenerated private HorizontalLayout horizontalLayoutLeftToolbar; @AutoGenerated private Button buttonLeft; @AutoGenerated private HorizontalLayout horizontalLayoutLeftToolbarLeft; @AutoGenerated private Button buttonExport; @AutoGenerated private Button buttonSynchronize; private static final long serialVersionUID = 1L; private static final Log logger = LogFactory.getLog(PolicyWorkspace.class); private final PolicyWorkspace self = this; private final OnDemandFileDownloader downloader = new OnDemandFileDownloader(this); private GitRepositoryContainer treeContainer; private static final Action EXPORT_REPOSITORY = new Action("Export Repository"); private static final Action SYNCHRONIZE_REPOSITORY = new Action("Synchronize"); private static final Action PUSH_CHANGES = new Action("Push Changes"); private static final Action CREATE_SUBDOMAIN = new Action("Create Sub Domain"); private static final Action RENAME_SUBDOMAIN = new Action("Rename Sub Domain"); private static final Action CREATE_NEWPOLICY = new Action("Create New Policy"); private static final Action RENAME_POLICY = new Action("Rename Policy"); private static final Action IMPORT_POLICY = new Action("Import Policy"); private static final Action DELETE_SUBDOMAIN = new Action("Delete Sub Domain"); private static final Action CLONE_POLICY = new Action("Clone Policy"); private static final Action VIEW_POLICY = new Action("View Policy"); private static final Action EDIT_POLICY = new Action("Edit Policy"); private static final Action EXPORT_POLICY = new Action("Export Policy"); private static final Action DELETE_POLICY = new Action("Delete Policy"); public static final String VIEWNAME = PolicyWorkspace.class.getCanonicalName(); /** * The constructor should first build the main layout, set the * composition root and then do any custom initialization. * * The constructor will not be automatically regenerated by the * visual editor. */ public PolicyWorkspace() { buildMainLayout(); setCompositionRoot(mainLayout); // // Initialize GUI // this.initializeTree(); this.initializeButtons(); } protected void initializeButtons() { buttonLeft.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; @Override public void buttonClick(ClickEvent event) { if (horizontalSplitPanel.getSplitPosition() == 100.0) horizontalSplitPanel.setSplitPosition(36, Unit.PERCENTAGE); else horizontalSplitPanel.setSplitPosition(0); } }); buttonRight.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; @Override public void buttonClick(ClickEvent event) { if (horizontalSplitPanel.getSplitPosition() == 0.0) horizontalSplitPanel.setSplitPosition(36, Unit.PERCENTAGE); else horizontalSplitPanel.setSplitPosition(100, Unit.PERCENTAGE); } }); // // Check user write-access // if (((XacmlAdminUI) UI.getCurrent()).isAuthorized(XacmlAdminAuthorization.AdminAction.ACTION_WRITE, XacmlAdminAuthorization.AdminResource.RESOURCE_POLICY_WORKSPACE)) { this.buttonSynchronize.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; @Override public void buttonClick(ClickEvent event) { self.synchronizeRepository(); } }); } else { logger.info("user not authorized to write, removing synchronize button."); this.buttonSynchronize.setVisible(false); } // // The export button is attached to dynamic downloader // downloader.extend(this.buttonExport); } protected void initializeTree() { // // This is where the user's Git repository is located // final Path gitPath = ((XacmlAdminUI) UI.getCurrent()).getUserGitPath(); // // Create our Git file system container // this.treeContainer = new GitRepositoryContainer(gitPath, gitPath.toFile()); // // Create our own filter to filter out File extensions and // also the Git directory. // this.treeContainer.setFilter(new FilenameFilter() { @Override public boolean accept(File dir, String name) { // // We don't want any of the hidden files // if (name.startsWith(".git") || name.equals(".DS_Store")) { return false; } // // We definitely want xml files // if (name.endsWith(".xml")) { return true; } // // We should test if its a directory, we want those // included. // Path path = Paths.get(dir.getAbsolutePath(), name); if (Files.isDirectory(path)) { return true; } logger.warn("Filtering out: " + path.toString()); return false; } }); // // Set TreeTables datasource as our git container // this.treeWorkspace.setContainerDataSource(this.treeContainer); // // Setup other properties etc. // this.treeWorkspace.setItemIconPropertyId("Icon"); this.treeWorkspace.setVisibleColumns(new Object[] { "Name", "Version", "Size", "Last Modified", "Status" }); this.treeWorkspace.setSizeFull(); this.treeWorkspace.setSelectable(true); this.treeWorkspace.setEditable(false); // // Expand the first couple of directories // for (Object id : this.treeWorkspace.getItemIds()) { this.treeWorkspace.setCollapsed(id, false); for (Object child : this.treeWorkspace.getChildren(id)) { this.treeWorkspace.setCollapsed(child, false); } } // // Respond to table selections // /* this.treeWorkspace.addValueChangeListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; @Override public void valueChange(ValueChangeEvent event) { File selection = (File) self.treeWorkspace.getValue(); if (selection != null) { self.buttonImport.setEnabled(selection.isDirectory()); self.buttonExport.setEnabled(selection.isFile()); } else { } } }); */ this.treeWorkspace.addItemClickListener(new ItemClickListener() { private static final long serialVersionUID = 1L; @Override public void itemClick(ItemClickEvent event) { if (event.isDoubleClick() && event.getItemId() instanceof File && ((File) event.getItemId()).isFile()) { self.openPolicyTab((File) event.getItemId(), true); } } }); // // Setup our action handlers // this.treeWorkspace.addActionHandler(new Handler() { private static final long serialVersionUID = 1L; @Override public Action[] getActions(Object target, Object sender) { if (target == null) { // // Nothing is selected, they right-clicked empty space // return new Action[] { SYNCHRONIZE_REPOSITORY, EXPORT_REPOSITORY, CREATE_SUBDOMAIN }; } if (!(target instanceof File)) { return null; } if (((File) target).isDirectory()) { // // Selected a directory // return new Action[] { CREATE_SUBDOMAIN, RENAME_SUBDOMAIN, DELETE_SUBDOMAIN, CREATE_NEWPOLICY, IMPORT_POLICY, PUSH_CHANGES }; } if (((File) target).isFile()) { // // Selected a policy file // return new Action[] { VIEW_POLICY, EDIT_POLICY, CLONE_POLICY, EXPORT_POLICY, RENAME_POLICY, DELETE_POLICY, PUSH_CHANGES }; } return null; } @Override public void handleAction(Action action, Object sender, Object target) { if (action == SYNCHRONIZE_REPOSITORY) { self.synchronizeRepository(); return; } if (action == EXPORT_REPOSITORY) { self.exportRepository(); return; } if (action == PUSH_CHANGES) { self.pushChanges((File) target); return; } if (action == CREATE_SUBDOMAIN) { self.editSubDomain((File) target, null); return; } if (action == RENAME_SUBDOMAIN) { self.editSubDomain((File) self.treeWorkspace.getParent(target), ((File) target).getName()); return; } if (action == CREATE_NEWPOLICY) { self.createPolicy((File) target); return; } if (action == RENAME_POLICY) { self.renamePolicy((File) target); return; } if (action == IMPORT_POLICY) { self.importPolicy((File) target); return; } if (action == DELETE_SUBDOMAIN) { self.deleteSubDomain((File) target); return; } if (action == CLONE_POLICY) { self.clonePolicy((File) target); return; } if (action == VIEW_POLICY) { self.openPolicyTab((File) target, true); return; } if (action == EDIT_POLICY) { self.openPolicyTab((File) target, false); return; } if (action == EXPORT_POLICY) { return; } if (action == DELETE_POLICY) { self.deletePolicy((File) target); return; } } }); // // Set the drop handler // this.treeWorkspace.setDragMode(TableDragMode.ROW); this.treeWorkspace.setDropHandler(this); // // Detect when a tab closes and remove it from the // tab sheet. // this.tabSheet.setCloseHandler(new CloseHandler() { private static final long serialVersionUID = 1L; @Override public void onTabClose(TabSheet tabsheet, Component tabContent) { logger.info("tabsheet closing: " + tabsheet.getCaption()); tabsheet.removeTab(tabsheet.getTab(tabContent)); } }); } protected void editSubDomain(final File parent, final String subdomain) { final SubDomainEditorWindow editor = new SubDomainEditorWindow(null); editor.setCaption((subdomain == null ? "Create New SubDomain" : "Edit SubDomain")); editor.setCloseShortcut(KeyCode.ESCAPE); editor.setModal(true); editor.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent event) { // // Did the user save it // if (editor.isSaved() == false) { return; } String newSubDomain = editor.getSubDomain(); if (newSubDomain == null) { logger.warn("Shouldn't have a null subdomain if the user clicked save button"); return; } // // New subdomain? // if (subdomain == null) { // // Create new one // Path createDir; if (parent == null) { // // New Root domain // createDir = Paths.get( ((XacmlAdminUI) UI.getCurrent()).getUserGitPath().toAbsolutePath().toString(), newSubDomain); } else { // // New subdomain // createDir = Paths.get(parent.getAbsolutePath(), newSubDomain); } try { // // Does the new subdomain exist? // Path newDir; if (Files.exists(createDir)) { // // It already exists // newDir = createDir; } else { // // Create it // newDir = Files.createDirectory(createDir); // // Create empty .gitignore file // Files.createFile(Paths.get(newDir.toString(), ".gitignore")); } // // Setup the TreeTable // File file = newDir.toFile(); if (parent == null) { Item item = self.treeWorkspace.addItem(file); if (item != null) { self.treeWorkspace.setCollapsed(file, false); self.treeWorkspace.select(file); } } else { Item item = self.treeWorkspace.addItem(file); if (item != null) { self.treeWorkspace.setParent(file, parent); self.treeWorkspace.setCollapsed(parent, false); self.treeWorkspace.select(file); } } } catch (IOException e) { logger.error("Failed to create subdomain: " + createDir.toString(), e); } } else { // // Get our paths // Path oldDir = Paths.get(parent.getAbsolutePath(), subdomain); Path newDir = Paths.get(parent.getAbsolutePath(), newSubDomain); try { // // Rename the subdomain // Files.move(oldDir, newDir); // // Add to the TreeTable // File newFile = newDir.toFile(); File oldFile = oldDir.toFile(); Item item = self.treeWorkspace.addItem(newFile); if (item != null) { self.treeWorkspace.setChildrenAllowed(newFile, true); // // Make sure its parent is the same as the old one, unless they // renamed the top-level. // Object parent = self.treeWorkspace.getParent(oldFile); if (parent != null) { self.treeWorkspace.setParent(newFile, parent); } // // Make any children of the old subdomain now children // of the new subdomain. // Collection<?> children = self.treeWorkspace.getChildren(oldFile); Iterator<?> iter = children.iterator(); while (iter.hasNext()) { Object child = iter.next(); self.treeWorkspace.setParent(child, newFile); } // // Finally remove the old subdomain // self.treeWorkspace.removeItem(oldFile); } } catch (IOException e) { logger.error( "Failed to rename subdomain: " + oldDir.toString() + " to: " + newDir.toString(), e); } } } }); editor.center(); UI.getCurrent().addWindow(editor); } protected void deleteSubDomain(final File subdomain) { String message = "Are you sure you want to delete subdomain\n" + subdomain.getName() + "\nThis will remove <B>ALL</B> of its subdomains and policy files."; ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm SubDomain Deletion", message, "Delete", "Cancel"); dialog.setContentMode(ContentMode.HTML); dialog.show(getUI(), new ConfirmDialog.Listener() { private static final long serialVersionUID = 1L; @Override public void onClose(ConfirmDialog dialog) { if (dialog.isConfirmed()) { // // Iterate the subdomain // try { Files.walkFileTree(Paths.get(subdomain.getAbsolutePath()), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path deleteFile, BasicFileAttributes attrs) throws IOException { try { boolean removeFromTree = deleteFile.getFileName().toString().endsWith(".xml"); Files.delete(deleteFile); if (removeFromTree) { self.treeWorkspace.removeItem(deleteFile.toFile()); } if (logger.isDebugEnabled()) { logger.debug("Deleted file: " + deleteFile.toString()); } } catch (IOException e) { logger.error("Failed to delete file: " + deleteFile.toString(), e); return FileVisitResult.TERMINATE; } return super.visitFile(deleteFile, attrs); } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { try { Files.delete(dir); self.treeWorkspace.removeItem(dir.toFile()); if (logger.isDebugEnabled()) { logger.debug("Deleted dir: " + dir.toString()); } } catch (IOException e) { logger.error("Failed to delete directory: " + dir.toString(), e); return FileVisitResult.TERMINATE; } return super.postVisitDirectory(dir, exc); } }); } catch (IOException e) { logger.error("Failed to walk subdomain: " + subdomain.getAbsolutePath(), e); } } } }, true); } protected void createPolicy(final File parentDirectory) { // // Construct our parameters // Path parent = Paths.get(parentDirectory.getAbsolutePath()); Path newFile = this.getNextFilename(parent, "Policy"); // // Run the window // this.runPolicyWindow("Create New Policy", parent, newFile, null, null); } protected void renamePolicy(final File policy) { // // Run the rename window // final RenamePolicyFileWindow window = new RenamePolicyFileWindow(policy.getName()); window.setCaption("Rename Policy"); window.setModal(true); window.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent event) { String newFilename = window.getNewFilename(); if (newFilename == null) { // // User cancelled // return; } Path newPolicy = Paths.get(policy.getParent(), newFilename); if (Files.exists(newPolicy)) { Notification.show("Cannot rename to an existing file", Notification.Type.ERROR_MESSAGE); return; } try { if (policy.renameTo(newPolicy.toFile()) == false) { throw new Exception("No known error, rename failed"); } self.treeContainer.updateItem(newPolicy.getParent().toFile()); } catch (Exception e) { Notification.show("Failed to rename file: " + e.getLocalizedMessage()); } } }); window.center(); UI.getCurrent().addWindow(window); } protected void clonePolicy(final File policy) { // // Figure out a new name for the cloned policy // Path policyClone = Paths.get(policy.getAbsolutePath()); Path newFile = this.getNextFilename(policyClone.getParent(), policy.getName()); if (newFile == null) { return; } // // Scan the policy in, replace policy ID's and rule ID's // Object policyData = new XACMLPolicyScanner(policyClone, new XACMLPolicyScanner.SimpleCallback() { @Override public CallbackResult onPreVisitRule(PolicyType parent, RuleType rule) { rule.setRuleId(((XacmlAdminUI) getUI()).newRuleID()); return CallbackResult.CONTINUE; } @Override public CallbackResult onPreVisitPolicySet(PolicySetType parent, PolicySetType policySet) { policySet.setPolicySetId(((XacmlAdminUI) getUI()).newPolicyID()); policySet.setVersion("1"); return CallbackResult.CONTINUE; } @Override public CallbackResult onPreVisitPolicy(PolicySetType parent, PolicyType policy) { policy.setPolicyId(((XacmlAdminUI) getUI()).newPolicyID()); policy.setVersion("1"); return CallbackResult.CONTINUE; } }).scan(); // // Run the window // this.runPolicyWindow("Clone Policy", newFile.getParent(), newFile.getFileName(), policyData, null); } protected void runPolicyWindow(String caption, final Path parentPath, final Path policyPath, final Object policyData, final Path oldPolicyFile) { // // Create our editor window // final PolicyNameEditorWindow editor = new PolicyNameEditorWindow( (policyPath != null ? policyPath.getFileName().toString() : null), policyData, ((XacmlAdminUI) getUI()).getPolicyAlgorithms(), ((XacmlAdminUI) getUI()).getRuleAlgorithms()); editor.setCaption(caption); editor.setCloseShortcut(KeyCode.ESCAPE); editor.setModal(true); editor.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent event) { // // Did the user hit save button or esc? // if (editor.isSaved() == false) { return; } final Object data = editor.getPolicyData(); String filename = editor.getPolicyFilename(); if (filename == null || data == null) { logger.warn("Editor said is was saved but filename/data is null."); return; } // // Determine new path // final Path newPolicyPath = Paths.get(parentPath.toString(), filename); // // Is it ok to overwrite the new file? // try { // // Handle if we are not replacing an old file and we are overwriting // an existing file. // if (self.isOverwritingAPolicy(newPolicyPath, oldPolicyFile) == false && Files.exists(newPolicyPath)) { // // Confirm they wanted to do this, and figure out // new version number. // String message = "You are overwriting a file: " + newPolicyPath.getFileName().toString(); ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm Policy File Overwriting", message, "Overwrite", "Cancel"); dialog.setData(false); dialog.setContentMode(ContentMode.HTML); dialog.setModal(true); dialog.show(getUI(), new ConfirmDialog.Listener() { private static final long serialVersionUID = 1L; @Override public void onClose(ConfirmDialog dialog) { if (dialog.isConfirmed()) { // // Yep the user wants to overwrite it // self.savePolicy(newPolicyPath, data, oldPolicyFile); // // Open it for editing // self.openPolicyTab(newPolicyPath.toFile(), false); } } }, true); // // Exit out of this thread // return; } } catch (Exception e) { logger.error(e); return; } // // Save it off // self.savePolicy(newPolicyPath, data, oldPolicyFile); // // Open it for editing // self.openPolicyTab(newPolicyPath.toFile(), false); } }); editor.center(); UI.getCurrent().addWindow(editor); } protected Path getNextFilename(Path parent, String filename) { filename = FilenameUtils.removeExtension(filename); Path newFile = null; int i = 0; while (true) { newFile = Paths.get(parent.toString(), String.format("%s(%02d)", filename, i++) + ".xml"); if (Files.notExists(newFile)) { return newFile; } if (i == 100) { logger.error("Could not construct a new name for cloned policy."); return null; } } } protected boolean isOverwritingAPolicy(Path newPolicyPath, Path oldPolicyPath) throws Exception { // // Check to see if we were editing an existing file. Then check if the // new file actually exists. Then check if we are overwriting the original old file // if (oldPolicyPath != null && Files.exists(newPolicyPath) && Files.isSameFile(newPolicyPath, oldPolicyPath)) { // // Yes its the same, overwriting it is expected. // logger.info("isOverwritingAPolicy"); return true; } return false; } protected void savePolicy(final Path newPolicyPath, final Object policyData, Path oldPolicyPath) { // // Are they overwriting another policy? // String version = "1.0"; boolean delete = false; if (oldPolicyPath != null) { // // This policy name was being edited. Is it still the same? // try { delete = true; if (Files.exists(newPolicyPath) && Files.isSameFile(newPolicyPath, oldPolicyPath)) { delete = false; } } catch (Exception e) { logger.error("Could not determine if same file", e); return; } logger.info("Deleting old file: " + delete); } // // Are we now overwriting another file? // if (Files.exists(newPolicyPath)) { // // Yes // logger.info("Overwriting file"); // // Overwrite is happening. Bump the version (IF WE CAN) // //TODO - What if user wants to change something other than the last number? For example, changing 1.5.23 to 2.0.0. //TODO We need a mechanism that allows the user to specify the new policy version (disallowing backtracking) if they desire //TODO and get that new number (if any) passed down to here. This code then becomes the "then" branch of "If new version has been specified..." try { int[] versionArray = StdPDPPolicy .versionStringToArray(XACMLPolicyScanner.getVersion(newPolicyPath)); // increment the right-most digit versionArray[versionArray.length - 1]++; version = StdPDPPolicy.versionArrayToString(versionArray); } catch (NumberFormatException | IOException e) { try { logger.warn("Previous version '" + XACMLPolicyScanner.getVersion(newPolicyPath) + "' not a series of itegers"); } catch (IOException e1) { logger.error("could not get previous version"); } //TODO - This may not be wise since the intent is to increase the version number. Perhaps we should abort this an go back to the user? version = "1.0"; } if (policyData instanceof PolicySetType) { ((PolicySetType) policyData).setVersion(version); } else if (policyData instanceof PolicyType) { ((PolicyType) policyData).setVersion(version); } } else { // // Nope, a completely new file // logger.info("New file"); } // // Is the root a PolicySet or Policy? // Path finalPolicyPath; if (policyData instanceof PolicySetType) { // // Write it out // finalPolicyPath = XACMLPolicyWriter.writePolicyFile(newPolicyPath, (PolicySetType) policyData); } else if (policyData instanceof PolicyType) { // // Write it out // finalPolicyPath = XACMLPolicyWriter.writePolicyFile(newPolicyPath, (PolicyType) policyData); } else { logger.error("Unknown data type sent back."); return; } // // Did it get written? // if (finalPolicyPath == null || !Files.exists(finalPolicyPath)) { logger.error("Failed to write policy file."); return; } // // Add it into our tree // this.addPolicyFileToTree(finalPolicyPath.getParent().toFile(), finalPolicyPath.toFile()); // // Do we need to delete the old file? // if (oldPolicyPath != null && delete) { try { Files.delete(oldPolicyPath); } catch (Exception e) { logger.error("Failed to delete old policy", e); } if (self.treeWorkspace.removeItem(oldPolicyPath.toFile()) == false) { logger.warn("Failed to remove old policy path"); } } } protected void deletePolicy(final File policy) { String message = "Are you sure you want to delete policy: " + policy.getName(); ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm Policy File Deletion", message, "Delete", "Cancel"); dialog.setContentMode(ContentMode.HTML); dialog.show(getUI(), new ConfirmDialog.Listener() { private static final long serialVersionUID = 1L; @Override public void onClose(ConfirmDialog dialog) { if (dialog.isConfirmed() && policy.delete()) { self.treeWorkspace.removeItem(policy); if (logger.isDebugEnabled()) { logger.debug("Deleted file: " + policy.toString()); } } } }, true); } protected void importPolicy(final File domain) { // // Get the current domain // if (!domain.isDirectory()) { logger.error("Table must have a directory selected to import the file."); return; } // // Create the upload window // final PolicyUploadWindow upload = new PolicyUploadWindow(Paths.get(domain.toURI())); upload.setCaption("Import Xacml 3.0 Policy File"); upload.setCloseShortcut(KeyCode.ESCAPE); upload.setModal(true); upload.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent e) { // // Was it successful? // Path newFile = upload.getUploadedFile(); if (newFile == null) { return; } // // Add it // self.addPolicyFileToTree(domain, newFile.toFile()); // // Are we importing anything in the policy file? // boolean importAttributes = upload.importAttributes(); boolean importObligations = upload.importObligations(); boolean importAdvice = upload.importAdvice(); if (importAttributes || importObligations || importAdvice) { // // Create our importer // XACMLPolicyImporter importer = new XACMLPolicyImporter(); importer.setImportAttributes(importAttributes); importer.setImportObligations(importObligations); importer.setImportAdvice(importAdvice); importer.setIgnoreStandardAttributes(upload.ignoreStandard()); // // Yes load and scan the policy // new XACMLPolicyScanner(newFile, importer).scan(); } } }); upload.center(); UI.getCurrent().addWindow(upload); } protected void addPolicyFileToTree(File domain, File file) { // // Add it into our tree // if (this.treeWorkspace.addItem(file) != null) { // // Make sure it has the right parent // this.treeWorkspace.setParent(file, domain); // // Select our new policy // self.treeWorkspace.select(file); } else { logger.error("Failed to add policy to workspace tree"); } } /* protected void publishPolicy(final File policy) { // // Get its ID // Item item = this.treeContainer.getItem(policy); if (item == null) { logger.error("Failed to get the item"); return; } Object policyData = item.getItemProperty("Data"); if (policyData == null) { logger.error("Failed to get item data property."); return; } String fullId = XACMLPolicyScanner.getID(policyData); String version = XACMLPolicyScanner.getVersion(policyData); if (fullId == null || version == null) { logger.error("Failed to get policy Id"); return; } List<String> ids = Lists.newArrayList(Splitter.on(':').split(fullId)); if (ids.isEmpty()) { logger.error("Couldn't parse policy Id"); return; } final String id = ids.get(ids.size() - 1) + "." + version; // // Is there only one group? // PAPEngine engine = ((XacmlAdminUI)getUI()).getPAPEngine(); Set<PDPGroup> groups; PDPGroup defaultGroup; try { groups = engine.getPDPGroups(); } catch (PAPException e) { String message = "Unable to retrieve Groups from server: " + e; logger.error(message, e); throw new RuntimeException(message); } try { defaultGroup = engine.getDefaultGroup(); } catch (PAPException e) { String message = "Unable to retrieve Default Group from server: " + e; logger.error(message, e); throw new RuntimeException(message); } if (groups.size() == 1) { this.doPublish(id, policy, defaultGroup); return; } // // Have user select a group // final SelectPDPGroupWindow window = new SelectPDPGroupWindow(groups, "Select PDP Group to publish in"); window.setCaption("Select PDP Group"); window.setCloseShortcut(KeyCode.ESCAPE); window.setModal(true); window.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent event) { PDPGroup group = window.selectedGroup(); if (group != null) { self.doPublish(id, policy, group); } } }); window.center(); UI.getCurrent().addWindow(window); } protected void doPublish(String id, File policy, PDPGroup group) { // // The policy status must be up-to-date // // TODO // // TODO - get list of referenced policies and publish // them first. // // // Publish the policy // PAPEngine engine = ((XacmlAdminUI)getUI()).getPAPEngine(); try (InputStream is = new FileInputStream(policy)) { engine.publishPolicy(id, policy.getName(), true, is, group); } catch (PAPException | IOException e) { logger.error("Failed to publish policy: ", e); } } */ protected void pushChanges(final File target) { try { // // Grab our working repository // Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath(); final Git git = Git.open(repoPath.toFile()); // // Get our status // final String base; Status status; if (target == null) { base = "."; } else { Path relativePath = repoPath.relativize(Paths.get(target.getPath())); base = relativePath.toString(); } if (logger.isDebugEnabled()) { logger.debug("Status on base: " + base); } status = git.status().addPath(base).call(); // // Check if its clean // if (status.isClean()) { // // Its clean // AdminNotification.warn(target.getName() + " is clean!"); return; } // // Create the window // final GitPushWindow window = new GitPushWindow(git, target, status); window.setCaption("Push Changes"); window.setModal(true); window.addCloseListener(new CloseListener() { private static final long serialVersionUID = 1L; @Override public void windowClose(CloseEvent e) { if (window.isSaved() == false) { return; } try { // // Needs to be added first // DirCache cache = git.add().addFilepattern(base).call(); for (int i = 0; i < cache.getEntryCount(); i++) { DirCacheEntry entry = cache.getEntry(i); if (logger.isDebugEnabled()) { logger.debug("Entry: " + entry); } } // // Next they need to be committed // RevCommit rev = git.commit().setMessage(window.getComment()).call(); if (logger.isDebugEnabled()) { logger.debug("RevCommit: " + rev); } // // Now we can push changes to the Git repository // Iterable<PushResult> results = git.push().call(); for (PushResult result : results) { logger.info(result); } // // Have the container fire an item set change notification // self.treeContainer.updateItem(target); } catch (NoWorkTreeException | GitAPIException e1) { logger.error(e); AdminNotification.error("Exception occurred while trying to push: " + e1); } } }); window.center(); UI.getCurrent().addWindow(window); } catch (IOException | GitAPIException e) { logger.error(e); AdminNotification.error("Exception occurred while trying to get status: " + e); } } protected void synchronizeRepository() { final GitSynchronizeWindow window = new GitSynchronizeWindow(); window.setCaption("Synchronize with server repository?"); window.setModal(true); window.center(); UI.getCurrent().addWindow(window); } protected void exportRepository() { this.buttonExport.click(); } @Override public String getFilename() { return "Repository.tgz"; } @Override public InputStream getStream() { // // Grab our working repository // final Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath(); Path workspacePath = ((XacmlAdminUI) getUI()).getUserWorkspace(); final Path tarFile = Paths.get(workspacePath.toString(), "Repository.tgz"); try (OutputStream os = Files.newOutputStream(tarFile)) { try (GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(os)) { try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(gzOut)) { tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); Files.walkFileTree(repoPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { if (dir.getFileName().toString().startsWith(".git")) { return FileVisitResult.SKIP_SUBTREE; } Path relative = repoPath.relativize(dir); if (relative.toString().isEmpty()) { return super.preVisitDirectory(dir, attrs); } TarArchiveEntry entry = new TarArchiveEntry(relative.toFile()); tarOut.putArchiveEntry(entry); tarOut.closeArchiveEntry(); return super.preVisitDirectory(dir, attrs); } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.getFileName().toString().endsWith(".xml") == false) { return super.visitFile(file, attrs); } Path relative = repoPath.relativize(file); TarArchiveEntry entry = new TarArchiveEntry(relative.toFile()); entry.setSize(Files.size(file)); tarOut.putArchiveEntry(entry); try { IOUtils.copy(Files.newInputStream(file), tarOut); } catch (IOException e) { logger.error(e); } tarOut.closeArchiveEntry(); return super.visitFile(file, attrs); } }); tarOut.finish(); } } } catch (IOException e) { logger.error(e); } try { return Files.newInputStream(tarFile); } catch (IOException e) { logger.error(e); } return null; } protected void openPolicyTab(File policy, boolean readOnly) { // // Sanity check // assert policy != null; assert policy.isFile(); if (policy == null || !policy.isFile()) { throw new IllegalArgumentException("You must specify a file."); } Status status; Path relativePath; String base; try { // // Grab our working repository // Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath(); final Git git = Git.open(repoPath.toFile()); // // Get our status // relativePath = repoPath.relativize(Paths.get(policy.getPath())); base = relativePath.toString(); if (logger.isDebugEnabled()) { logger.debug("Status on base: " + base); } status = git.status().addPath(base).call(); } catch (NoWorkTreeException | IOException | GitAPIException e) { logger.error("Failed to get status on " + policy + " " + e); AdminNotification.error("Could not get Git status on the file."); return; } // // Check if its clean // if (status.isClean() == false) { // // Check if its conflicting // for (String conflict : status.getConflicting()) { if (conflict.equals(base)) { // // Yes - we won't be able to edit it // AdminNotification.error("Policy has conflicts with master, please synchronize the repository."); return; } } } // // Check to see if there already is a tab open // Iterator<Component> iter = self.tabSheet.iterator(); while (iter.hasNext()) { Component c = iter.next(); if (c instanceof PolicyEditor) { Object data = ((PolicyEditor) c).getData(); if (data != null && data instanceof File && ((File) data).equals(policy)) { self.tabSheet.setSelectedTab(c); return; } } } // // No tab is open, create a new one // PolicyEditor editor = null; try { editor = new PolicyEditor(policy, this.treeContainer, readOnly); } catch (IOException e) { logger.error("Failed to open policy"); editor = null; } if (editor != null) { editor.setWidth("100%"); Tab tab = self.tabSheet.addTab(editor); editor.setTab(tab); tab.setClosable(true); self.tabSheet.setSelectedTab(editor); } else { AdminNotification.error("The Policy File is not a Xacml 3.0 policy."); } } @Override public void drop(DragAndDropEvent event) { Transferable t = event.getTransferable(); Component source = t.getSourceComponent(); if (source != this.treeWorkspace) { assert false; throw new IllegalArgumentException(); } TableTransferable tt = (TableTransferable) t; File sourceFile = (File) tt.getItemId(); AbstractSelectTargetDetails target = (AbstractSelectTargetDetails) event.getTargetDetails(); File targetFile = (File) target.getItemIdOver(); if (sourceFile.isFile() && targetFile != null && targetFile.isDirectory()) { // // Construct destination filename // Path dest = targetFile.toPath().resolve(sourceFile.getName()); // // Check if the target domain exists // if (Files.exists(dest)) { // // Prompt the user // Notification.show("A policy file with that name already exists in that directory.", Notification.Type.ERROR_MESSAGE); } else { // // Go ahead and rename it // this.renamePolicyFile(sourceFile, dest.toFile(), targetFile); } } } protected void renamePolicyFile(File sourceFile, File dest, File parent) { try { if (sourceFile.renameTo(dest)) { this.treeContainer.setParent(sourceFile, parent); this.treeContainer.updateItem(parent); } } catch (Exception e) { String error = "Failed to rename " + sourceFile + " to: " + dest + System.lineSeparator() + e.getLocalizedMessage(); logger.error(error); AdminNotification.error(error); } } @Override public AcceptCriterion getAcceptCriterion() { return AcceptAll.get(); } @AutoGenerated private VerticalLayout buildMainLayout() { // common part: create layout mainLayout = new VerticalLayout(); mainLayout.setImmediate(false); mainLayout.setWidth("100%"); mainLayout.setHeight("100%"); mainLayout.setMargin(false); // top-level component properties setWidth("100.0%"); setHeight("100.0%"); // horizontalSplitPanel horizontalSplitPanel = buildHorizontalSplitPanel(); mainLayout.addComponent(horizontalSplitPanel); mainLayout.setExpandRatio(horizontalSplitPanel, 1.0f); return mainLayout; } @AutoGenerated private HorizontalSplitPanel buildHorizontalSplitPanel() { // common part: create layout horizontalSplitPanel = new HorizontalSplitPanel(); horizontalSplitPanel.setImmediate(false); horizontalSplitPanel.setWidth("100.0%"); horizontalSplitPanel.setHeight("100.0%"); // verticalLayoutLeftPanel verticalLayoutLeftPanel = buildVerticalLayoutLeftPanel(); horizontalSplitPanel.addComponent(verticalLayoutLeftPanel); // verticalLayoutRightPanel verticalLayoutRightPanel = buildVerticalLayoutRightPanel(); horizontalSplitPanel.addComponent(verticalLayoutRightPanel); return horizontalSplitPanel; } @AutoGenerated private VerticalLayout buildVerticalLayoutLeftPanel() { // common part: create layout verticalLayoutLeftPanel = new VerticalLayout(); verticalLayoutLeftPanel.setImmediate(false); verticalLayoutLeftPanel.setWidth("100.0%"); verticalLayoutLeftPanel.setHeight("100.0%"); verticalLayoutLeftPanel.setMargin(true); verticalLayoutLeftPanel.setSpacing(true); // horizontalLayoutLeftToolbar horizontalLayoutLeftToolbar = buildHorizontalLayoutLeftToolbar(); verticalLayoutLeftPanel.addComponent(horizontalLayoutLeftToolbar); // treeWorkspace treeWorkspace = new TreeTable(); treeWorkspace.setImmediate(true); treeWorkspace.setWidth("100.0%"); treeWorkspace.setHeight("100.0%"); verticalLayoutLeftPanel.addComponent(treeWorkspace); verticalLayoutLeftPanel.setExpandRatio(treeWorkspace, 1.0f); return verticalLayoutLeftPanel; } @AutoGenerated private HorizontalLayout buildHorizontalLayoutLeftToolbar() { // common part: create layout horizontalLayoutLeftToolbar = new HorizontalLayout(); horizontalLayoutLeftToolbar.setImmediate(false); horizontalLayoutLeftToolbar.setWidth("100.0%"); horizontalLayoutLeftToolbar.setHeight("-1px"); horizontalLayoutLeftToolbar.setMargin(false); horizontalLayoutLeftToolbar.setSpacing(true); // horizontalLayoutLeftToolbarLeft horizontalLayoutLeftToolbarLeft = buildHorizontalLayoutLeftToolbarLeft(); horizontalLayoutLeftToolbar.addComponent(horizontalLayoutLeftToolbarLeft); // buttonLeft buttonLeft = new Button(); buttonLeft.setCaption("<<"); buttonLeft.setImmediate(true); buttonLeft.setDescription("Minimize left panel."); buttonLeft.setWidth("-1px"); buttonLeft.setHeight("-1px"); horizontalLayoutLeftToolbar.addComponent(buttonLeft); horizontalLayoutLeftToolbar.setComponentAlignment(buttonLeft, new Alignment(34)); return horizontalLayoutLeftToolbar; } @AutoGenerated private HorizontalLayout buildHorizontalLayoutLeftToolbarLeft() { // common part: create layout horizontalLayoutLeftToolbarLeft = new HorizontalLayout(); horizontalLayoutLeftToolbarLeft.setImmediate(false); horizontalLayoutLeftToolbarLeft.setWidth("-1px"); horizontalLayoutLeftToolbarLeft.setHeight("-1px"); horizontalLayoutLeftToolbarLeft.setMargin(false); horizontalLayoutLeftToolbarLeft.setSpacing(true); // buttonSynchronize buttonSynchronize = new Button(); buttonSynchronize.setCaption("Synchronize Repository"); buttonSynchronize.setImmediate(true); buttonSynchronize.setDescription("Synchronize local repository with main branch."); buttonSynchronize.setWidth("-1px"); buttonSynchronize.setHeight("-1px"); horizontalLayoutLeftToolbarLeft.addComponent(buttonSynchronize); // buttonExport buttonExport = new Button(); buttonExport.setCaption("Export Workspace"); buttonExport.setImmediate(true); buttonExport.setDescription("Export your workspace to your local drive."); buttonExport.setWidth("-1px"); buttonExport.setHeight("-1px"); horizontalLayoutLeftToolbarLeft.addComponent(buttonExport); return horizontalLayoutLeftToolbarLeft; } @AutoGenerated private VerticalLayout buildVerticalLayoutRightPanel() { // common part: create layout verticalLayoutRightPanel = new VerticalLayout(); verticalLayoutRightPanel.setImmediate(false); verticalLayoutRightPanel.setWidth("100.0%"); verticalLayoutRightPanel.setHeight("-1px"); verticalLayoutRightPanel.setMargin(true); verticalLayoutRightPanel.setSpacing(true); // horizontalLayoutRightToolbar horizontalLayoutRightToolbar = buildHorizontalLayoutRightToolbar(); verticalLayoutRightPanel.addComponent(horizontalLayoutRightToolbar); // tabSheet tabSheet = new TabSheet(); tabSheet.setImmediate(true); tabSheet.setWidth("100.0%"); tabSheet.setHeight("-1px"); verticalLayoutRightPanel.addComponent(tabSheet); verticalLayoutRightPanel.setExpandRatio(tabSheet, 1.0f); return verticalLayoutRightPanel; } @AutoGenerated private HorizontalLayout buildHorizontalLayoutRightToolbar() { // common part: create layout horizontalLayoutRightToolbar = new HorizontalLayout(); horizontalLayoutRightToolbar.setImmediate(false); horizontalLayoutRightToolbar.setWidth("100.0%"); horizontalLayoutRightToolbar.setHeight("-1px"); horizontalLayoutRightToolbar.setMargin(false); horizontalLayoutRightToolbar.setSpacing(true); // buttonRight buttonRight = new Button(); buttonRight.setCaption(">>"); buttonRight.setImmediate(true); buttonRight.setDescription("Restore left panel."); buttonRight.setWidth("-1px"); buttonRight.setHeight("-1px"); horizontalLayoutRightToolbar.addComponent(buttonRight); return horizontalLayoutRightToolbar; } }