/** {@inheritDoc} */ @Override public Entry getEntry(DN entryDN) throws DirectoryException { // If the requested entry was null, then throw an exception. if (entryDN == null) { throw new DirectoryException( DirectoryServer.getServerErrorResultCode(), ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID())); } // If the requested entry was the backend base entry, then retrieve it. if (entryDN.equals(backupBaseDN)) { return backupBaseEntry.duplicate(true); } // See if the requested entry was one level below the backend base entry. // If so, then it must point to a backup directory. Otherwise, it must be // two levels below the backup base entry and must point to a specific // backup. DN parentDN = entryDN.getParentDNInSuffix(); if (parentDN == null) { Message message = ERR_BACKUP_INVALID_BASE.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } else if (parentDN.equals(backupBaseDN)) { return getBackupDirectoryEntry(entryDN); } else if (backupBaseDN.equals(parentDN.getParentDNInSuffix())) { return getBackupEntry(entryDN); } else { Message message = ERR_BACKUP_INVALID_BASE.get(String.valueOf(entryDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, backupBaseDN, null); } }
/** * If the entry has changed its name, make the required calls to set up the display tree and make * the directory changes. * * @param oldEntry the old entry containing teh old set of attributes. * @param newEntry the new entry containing the replacement set of attributes. */ private boolean handleAnyNameChange(DXEntry oldEntry, DXEntry newEntry) { // check for 'simple' rename from the tree, with no attributes involved. RDN oldRDN = oldEntry.getRDN(); RDN newRDN = newEntry.getRDN(); DN oldDN = oldEntry.getDN(); DN newDN = newEntry.getDN(); if (oldDN.equals(newDN)) return true; // nothing to see here, just move along. if (oldEntry.size() == 0 && newEntry.size() == 0) // a very simple rename, probably from the tree { return moveTree(oldDN, newDN); } else if (oldRDN.isMultiValued() == false && newRDN.isMultiValued() == false) { return renameSingleValuedRDNS(oldEntry, newEntry); } else { return renameComplexMultiValuedRDNs(oldEntry, newEntry); } }
/** * Test the attribute types of the search filter for access. This method supports the search * right. * * @param container The container used in the access evaluation. * @param filter The filter to check access on. * @return True if all attribute types in the filter have access. * @throws DirectoryException If there is a problem matching the entry using the provided filter. */ private boolean testFilter(AciLDAPOperationContainer container, SearchFilter filter) throws DirectoryException { boolean ret = true; // If the resource entry has a dn equal to "cn=debugsearch" and it // contains the special attribute type "debugsearchindex", then the // resource entry is a pseudo entry created for debug purposes. // Return true if that is the case. if (debugSearchIndexDN.equals(container.getResourceDN()) && container.getResourceEntry().hasAttribute(debugSearchIndex)) { return true; } switch (filter.getFilterType()) { case AND: case OR: { for (SearchFilter f : filter.getFilterComponents()) { if (!testFilter(container, f)) { return false; } } break; } case NOT: { SearchFilter f = filter.getNotComponent(); ret = testFilter(container, f); break; } default: { AttributeType attrType = filter.getAttributeType(); container.setCurrentAttributeType(attrType); ret = accessAllowed(container); } } return ret; }
/** * Check access using the specified container. This container will have all of the information to * gather applicable ACIs and perform evaluation on them. * * @param container An ACI operation container which has all of the information needed to check * access. * @return True if access is allowed. */ boolean accessAllowed(AciContainer container) { DN dn = container.getResourceEntry().getDN(); // For ACI_WRITE_ADD and ACI_WRITE_DELETE set the ACI_WRITE // right. if (container.hasRights(ACI_WRITE_ADD) || container.hasRights(ACI_WRITE_DELETE)) { container.setRights(container.getRights() | ACI_WRITE); } // Check if the ACI_SELF right needs to be set (selfwrite right). // Only done if the right is ACI_WRITE, an attribute value is set // and that attribute value is a DN. if ((container.getCurrentAttributeValue() != null) && (container.hasRights(ACI_WRITE)) && (isAttributeDN(container.getCurrentAttributeType()))) { String DNString = null; try { DNString = container.getCurrentAttributeValue().getValue().toString(); DN tmpDN = DN.decode(DNString); // Have a valid DN, compare to clientDN to see if the ACI_SELF // right should be set. if (tmpDN.equals(container.getClientDN())) { container.setRights(container.getRights() | ACI_SELF); } } catch (DirectoryException ex) { // Log a message and keep going. Message message = WARN_ACI_NOT_VALID_DN.get(DNString); logError(message); } } // Check proxy authorization only if the entry has not already been // processed (working on a new entry). If working on a new entry, // then only do a proxy check if the right is not set to ACI_PROXY // and the proxied authorization control has been decoded. if (!container.hasSeenEntry()) { if (container.isProxiedAuthorization() && !container.hasRights(ACI_PROXY) && !container.hasRights(ACI_SKIP_PROXY_CHECK)) { int currentRights = container.getRights(); // Save the current rights so they can be put back if on // success. container.setRights(ACI_PROXY); // Switch to the original authorization entry, not the proxied // one. container.useOrigAuthorizationEntry(true); if (!accessAllowed(container)) { return false; } // Access is ok, put the original rights back. container.setRights(currentRights); // Put the proxied authorization entry back to the current // authorization entry. container.useOrigAuthorizationEntry(false); } // Set the seen flag so proxy processing is not performed for this // entry again. container.setSeenEntry(true); } /* * First get all allowed candidate ACIs. */ LinkedList<Aci> candidates = aciList.getCandidateAcis(dn); /* * Create an applicable list of ACIs by target matching each * candidate ACI against the container's target match view. */ createApplicableList(candidates, container); /* * Evaluate the applicable list. */ boolean ret = testApplicableLists(container); // Build summary string if doing geteffectiverights eval. if (container.isGetEffectiveRightsEval()) { AciEffectiveRights.createSummary(container, ret, "main"); } return ret; }
/** * Updates the config file during the upgrade process. * * @param configPath The original path to the file. * @param filter The filter to select entries. Only useful for modify change type. * @param changeType The change type which must be applied to ldif lines. * @param ldifLines The change record ldif lines. For ADD change type, the first line must be the * dn. For DELETE change type, the first and only line must be the dn. * @throws IOException If an Exception occurs during the input output methods. * @return The changes number that have occurred. */ static int updateConfigFile( final String configPath, final Filter filter, final ChangeOperationType changeType, final String... ldifLines) throws IOException { final File original = new File(configPath); final File copyConfig = File.createTempFile("copyConfig", ".tmp", original.getParentFile()); int changeCount = 0; LDIFEntryReader entryReader = null; LDIFEntryWriter writer = null; try { final Schema schema = getUpgradeSchema(); entryReader = new LDIFEntryReader(new FileInputStream(configPath)).setSchema(schema); writer = new LDIFEntryWriter(new FileOutputStream(copyConfig)); writer.setWrapColumn(80); // Writes the header on the new file. writer.writeComment(INFO_CONFIG_FILE_HEADER.get()); writer.setWrapColumn(0); boolean entryAlreadyExist = false; DN ldifDN = null; if (filter == null && (changeType == ADD || changeType == DELETE)) { // The first line should start with dn: ldifDN = DN.valueOf(ldifLines[0].replaceFirst("dn: ", "")); } final Filter f = filter != null ? filter : Filter.alwaysFalse(); final Matcher matcher = f.matcher(schema); while (entryReader.hasNext()) { Entry entry = entryReader.readEntry(); final DN entryDN = entry.getName(); // Searching for the related entries if (changeType == MODIFY && matcher.matches(entry) == ConditionResult.TRUE) { try { final ModifyRequest mr = Requests.newModifyRequest(readLDIFLines(entryDN, changeType, ldifLines)); entry = Entries.modifyEntryPermissive(entry, mr.getModifications()); changeCount++; logger.debug( LocalizableMessage.raw("The following entry has been modified : %s", entryDN)); } catch (Exception ex) { logger.error(LocalizableMessage.raw(ex.getMessage())); } } if (entryDN.equals(ldifDN)) { logger.debug(LocalizableMessage.raw("Entry %s found", entryDN)); entryAlreadyExist = true; if (changeType == DELETE) { entry = null; changeCount++; logger.debug( LocalizableMessage.raw("The following entry has been deleted : %s", entryDN)); } } if (entry != null) { writer.writeEntry(entry); } } if (changeType == ADD && !entryAlreadyExist) { final AddRequest ar = Requests.newAddRequest(ldifLines); writer.writeEntry(ar); logger.debug( LocalizableMessage.raw( "Entry successfully added %s in %s", ldifDN, original.getAbsolutePath())); changeCount++; } } catch (Exception ex) { throw new IOException(ex.getMessage()); } finally { // The reader and writer must be close before renaming files. // Otherwise it causes exceptions under windows OS. StaticUtils.close(entryReader, writer); } try { // Renaming the file, overwriting previous one. rename(copyConfig, new File(configPath)); } catch (IOException e) { logger.error(LocalizableMessage.raw(e.getMessage())); deleteRecursively(original); throw e; } return changeCount; }
private void displayEntry( DXEntry entry, DataBrokerQueryInterface ds, boolean storeOriginalEntry) { myEditor.stopCellEditing(); // checkedDN = null; // hack - resets promptForSave. // Store original Entry for reset if (entry != null && storeOriginalEntry && entry.getStatus() == DXEntry.NORMAL) originalEntry = new DXEntry(entry); // Set the globals... currentEntry = entry; dataSource = ds; if (entry != null && entry.size() == 0) { // If there is an entry and its size is zero - it's probably a virtual entry. // We need to give the user the option of adding an object class to it i.e. so that // it can be added to the directory as a real entry. // // Disable all the buttons except the 'Change Class' button - but rename this button // to 'Add Class' so the user hopefully has a bit more of an idea about what is going on. // Sets editor to a blank screen... tableData.clear(); // Disable all buttons except the 'Change Class' button - rename this one... submit.setEnabled(false); reset.setEnabled(false); changeClass.setText(CBIntText.get("Add Class")); changeClass.setEnabled(true); opAttrs.setEnabled(false); virtualEntry = true; return; } virtualEntry = false; // Isn't a virtual entry... if (entry != null) currentDN = entry.getDN(); // May have been changed to 'Add Class'... changeClass.setText(CBIntText.get("Change Class")); // Some quick faffing around, to see if we're coming back from a // change classes operation. if (classChangedOriginalEntry != null) { // If they have the same name, then we're reviewing the same entry - otherwise we've moved on if (entry == null || entry.getDN().equals(classChangedOriginalEntry.getDN()) == false) classChangedOriginalEntry = null; } /* * Check that we're not displaying a new entry, and leaving unsaved changes * behind. * * This turns out to be quite tricky, and involves a bunch 'o special cases. * * First check whether the table data has changed (if not, do nothing) * -> if the new entry is null, prompt user to save * -> OR if the DN has changed, and it wasn't due to a rename, prompt user to save * */ if (tableData.changedByUser()) // user made changes - were they saved? (i.e., are we { // displaying the result of those changes?) boolean prompt = false; DXEntry oldEntry = tableData.getOldEntry(); if (oldEntry != null) { /* * The code below is simply checking to see if the name of the * new entry is different from the old entry, and if it is, * whether that's due to the old entry being renamed. */ if (entry == null) { prompt = true; } // TE: added the isEmpty check see bug: 3194. else if (!oldEntry.getDN().isEmpty() && entry.getDN().equals(oldEntry.getDN()) == false) { DN oldParent = oldEntry.getDN().getParent(); DN newParent = entry.getDN().getParent(); if (oldParent.equals(newParent) == false) { prompt = true; } else { if (entry.getDN().getLowestRDN().equals(tableData.getRDN()) == false) { prompt = true; } } } if (prompt) // yes, there is a risk of data loss - prompt the user. { checkForUnsavedChanges(); // see if the user wants to save their data } } } myEditor.setDataSource( ds); // Sets the DataBrokerQueryInterface in AttributeValueCellEditor used to get the syntax // of attributes. // only enable buttons if DataBrokerQueryInterface // is valid *and* we can modify data... if (dataSource == null || entry == null || dataSource.isModifiable() == false) { setReadWrite(false, entry); } else { setReadWrite(true, entry); } // myEditor.stopCellEditing(); if (entry != null) { entry.expandAllAttributes(); currentDN = entry.getDN(); tableData.insertAttributes(entry); popupTableTool.setDN(currentDN); // Sets the DN in SmartPopupTableTool. myEditor.setDN( currentDN); // Sets the DN in the attributeValueCellEditor which can be used to identify // the entry that is being modified/ } else { tableData.clear(); // Sets editor to a blank screen. } tableScroller.getVerticalScrollBar().setValue(0); // Sets the scroll bar back to the top. }
/** Opens the change class dialog. */ public void changeClass() { // JPanel mainPanel /* * MINOR MAGIC * * This code reuses the 'new entry window'. In order to make things * sane, we prompt the user to save any serious changes before continuing. * (Things can get really wierd if the user changes the name and then * tries to change the objectclass - best to avoid the whole issue.) */ myEditor.stopCellEditing(); if (virtualEntry) { doVirtualEntryDisplay(); return; } /* * classChangedOriginalEntry saves the original state of the entry * between visits to NewEntryWin. (- I wonder if it would be neater * to just reset the 'oldEntry' state of the table every time? ). * Check it's not been set already (i.e. Pathological User is paying * multiple visits to the NewEntryWin.) */ if (classChangedOriginalEntry == null) classChangedOriginalEntry = tableData.getOldEntry(); DXEntry newEntry = tableData.getNewEntry(); DN newDN = newEntry.getDN(); /* * Pathalogical user has messed with the name, *and* wants to * change the object classes... */ if (newDN.equals(classChangedOriginalEntry.getDN()) == false) { checkForUnsavedChanges(); /* if (promptForSave() == false) // we may need to reset the 'newEntry' data { // if the user discards their changes. tableData.reset(); // resets the table before going on. newEntry = tableData.getNewEntry(); newDN = newEntry.getDN(); } else // user has saved data - so now we need to reset the 'classChangedOriginalEntry' { */ // to the changed (and hopefully saved!) data. // NB: If the directory write fails, then the change classes will also fail... classChangedOriginalEntry = tableData.getNewEntry(); } /* * Open NewEntryWin, allowing the user to reset the objectclass attribute. */ /* NewEntryWin userData = new NewEntryWin(newDN.parentDN(), newDN, dataSource, newEntry.getAsNonNullAttributes(), newDN.getLowestRDN().toString(), TableAttributeEditor.this, CBUtility.getParentFrame(mainPanel)); */ if (dataSource.getSchemaOps() == null) { JOptionPane.showMessageDialog( owner, CBIntText.get( "Because there is no schema currently published by the\ndirectory, changing an entry's object class is unavailable."), CBIntText.get("No Schema"), JOptionPane.INFORMATION_MESSAGE); return; } else { ChangeObjectClassWin userData = new ChangeObjectClassWin( dataSource, newDN, newEntry.getAsNonNullAttributes(), this, CBUtility.getParentFrame(this), false); userData.setSize(400, 250); CBUtility.center(userData, owner); // TE: centres window. userData.setVisible(true); } }
/** {@inheritDoc} */ @Override public void search(SearchOperation searchOperation) throws DirectoryException { // Get the base entry for the search, if possible. If it doesn't exist, // then this will throw an exception. DN baseDN = searchOperation.getBaseDN(); Entry baseEntry = getEntry(baseDN); // Look at the base DN and see if it's the backup base DN, a backup // directory entry DN, or a backup entry DN. DN parentDN; SearchScope scope = searchOperation.getScope(); SearchFilter filter = searchOperation.getFilter(); if (backupBaseDN.equals(baseDN)) { if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) && filter.matchesEntry(baseEntry)) { searchOperation.returnEntry(baseEntry, null); } if (scope != SearchScope.BASE_OBJECT && !backupDirectories.isEmpty()) { AttributeType backupPathType = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); for (File f : backupDirectories) { // Check to see if the descriptor file exists. If not, then skip this // backup directory. File descriptorFile = new File(f, BACKUP_DIRECTORY_DESCRIPTOR_FILE); if (!descriptorFile.exists()) { continue; } DN backupDirDN = makeChildDN(backupBaseDN, backupPathType, f.getAbsolutePath()); Entry backupDirEntry; try { backupDirEntry = getBackupDirectoryEntry(backupDirDN); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } if (filter.matchesEntry(backupDirEntry)) { searchOperation.returnEntry(backupDirEntry, null); } if (scope != SearchScope.SINGLE_LEVEL) { List<Attribute> attrList = backupDirEntry.getAttribute(backupPathType); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true); for (String backupID : backupDirectory.getBackups().keySet()) { DN backupEntryDN = makeChildDN(backupDirDN, idType, backupID); Entry backupEntry = getBackupEntry(backupEntryDN); if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } } } } } } } else if (backupBaseDN.equals(parentDN = baseDN.getParentDNInSuffix())) { Entry backupDirEntry = getBackupDirectoryEntry(baseDN); if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) && filter.matchesEntry(backupDirEntry)) { searchOperation.returnEntry(backupDirEntry, null); } if (scope != SearchScope.BASE_OBJECT) { AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); List<Attribute> attrList = backupDirEntry.getAttribute(t); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); AttributeType idType = DirectoryServer.getAttributeType(ATTR_BACKUP_ID, true); for (String backupID : backupDirectory.getBackups().keySet()) { DN backupEntryDN = makeChildDN(baseDN, idType, backupID); Entry backupEntry = getBackupEntry(backupEntryDN); if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } } } } } else { if (parentDN == null || !backupBaseDN.equals(parentDN.getParentDNInSuffix())) { Message message = ERR_BACKUP_NO_SUCH_ENTRY.get(String.valueOf(backupBaseDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } if (scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) { Entry backupEntry = getBackupEntry(baseDN); if (backupEntry == null) { Message message = ERR_BACKUP_NO_SUCH_ENTRY.get(String.valueOf(backupBaseDN)); throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); } if (filter.matchesEntry(backupEntry)) { searchOperation.returnEntry(backupEntry, null); } } } }
/** {@inheritDoc} */ @Override public long numSubordinates(DN entryDN, boolean subtree) throws DirectoryException { // If the requested entry was null, then return undefined. if (entryDN == null) { return -1; } // If the requested entry was the backend base entry, then return // the number of backup directories. if (backupBaseDN.equals(entryDN)) { long count = 0; for (File f : backupDirectories) { // Check to see if the descriptor file exists. If not, then skip this // backup directory. File descriptorFile = new File(f, BACKUP_DIRECTORY_DESCRIPTOR_FILE); if (!descriptorFile.exists()) { continue; } // If subtree is included, count the number of entries for each // backup directory. if (subtree) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(f.getPath()); count += backupDirectory.getBackups().keySet().size(); } catch (Exception e) { return -1; } } count++; } return count; } // See if the requested entry was one level below the backend base entry. // If so, then it must point to a backup directory. Otherwise, it must be // two levels below the backup base entry and must point to a specific // backup. DN parentDN = entryDN.getParentDNInSuffix(); if (parentDN == null) { return -1; } else if (backupBaseDN.equals(parentDN)) { long count = 0; Entry backupDirEntry = getBackupDirectoryEntry(entryDN); AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true); List<Attribute> attrList = backupDirEntry.getAttribute(t); if (attrList != null && !attrList.isEmpty()) { for (AttributeValue v : attrList.get(0)) { try { BackupDirectory backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString()); count += backupDirectory.getBackups().keySet().size(); } catch (Exception e) { return -1; } } } return count; } else if (backupBaseDN.equals(parentDN.getParentDNInSuffix())) { return 0; } else { return -1; } }