001/* 002 * Copyright 2012-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2012-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2015-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds; 037 038 039 040import java.util.Date; 041 042import com.unboundid.ldap.sdk.Entry; 043import com.unboundid.ldap.sdk.LDAPException; 044import com.unboundid.ldap.sdk.ReadOnlyEntry; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.unboundidds.controls. 047 SoftDeletedEntryAccessRequestControl; 048import com.unboundid.util.NotMutable; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*; 053 054 055 056/** 057 * This class provides a data structure for representing information about a 058 * soft-deleted entry, which results from a soft delete operation that has 059 * caused the entry to be hidden so that it is not accessible to clients under 060 * normal circumstances, rather than causing the entry to be completely removed 061 * from the server. 062 * <BR> 063 * <BLOCKQUOTE> 064 * <B>NOTE:</B> This class, and other classes within the 065 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 066 * supported for use against Ping Identity, UnboundID, and 067 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 068 * for proprietary functionality or for external specifications that are not 069 * considered stable or mature enough to be guaranteed to work in an 070 * interoperable way with other types of LDAP servers. 071 * </BLOCKQUOTE> 072 * <BR> 073 * A soft-deleted entry will have its RDN altered to include the entryUUID for 074 * the original entry, will be updated to include the "ds-soft-delete-entry" 075 * auxiliary object class, and will have additional metadata attributes added to 076 * it which may include: 077 * <UL> 078 * <LI> 079 * ds-soft-delete-from-dn -- This specifies the DN assigned to the entry 080 * before it was converted to a soft-deleted entry. 081 * </LI> 082 * <LI> 083 * ds-soft-delete-timestamp -- This specifies the time that the entry was 084 * converted to a soft-deleted entry. 085 * </LI> 086 * <LI> 087 * ds-soft-delete-requester-dn -- This specifies the DN of the user who 088 * requested the soft delete operation. 089 * </LI> 090 * <LI> 091 * ds-soft-delete-requester-ip-address -- This specifies the IP address of 092 * the client that requested the soft delete operation. 093 * </LI> 094 * </UL> 095 * <BR><BR> 096 * Soft-deleted entries may only be retrieved by users who have the 097 * soft-delete-read privilege, and then only by clients who issue a search 098 * request with one or more of the following characteristics: 099 * <UL> 100 * <LI> 101 * The search operation has a scope of baseObject and a base DN which 102 * specifically targets a soft-deleted entry. 103 * </LI> 104 * <LI> 105 * The search operation includes a filter with a component that will 106 * specifically match entries that have the ds-soft-delete-entry object 107 * class (e.g., "(objectClass=ds-soft-delete-entry)"). 108 * </LI> 109 * <LI> 110 * The search operation includes a 111 * {@link SoftDeletedEntryAccessRequestControl}. 112 * </LI> 113 * </UL> 114 */ 115@NotMutable() 116@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 117public final class SoftDeletedEntry 118 extends ReadOnlyEntry 119{ 120 /** 121 * The name of the attribute that will be included in a soft-deleted entry to 122 * indicate the original DN the entry held before it was converted to a 123 * soft-deleted entry. 124 */ 125 public static final String ATTR_SOFT_DELETE_FROM_DN = 126 "ds-soft-delete-from-dn"; 127 128 129 130 /** 131 * The name of the attribute that will be included in a soft-deleted entry to 132 * indicate the DN of the user that requested the soft delete operation. 133 */ 134 public static final String ATTR_SOFT_DELETE_REQUESTER_DN = 135 "ds-soft-delete-requester-dn"; 136 137 138 139 /** 140 * The name of the attribute that will be included in a soft-deleted entry to 141 * indicate the IP address of the client that requested the soft delete 142 * operation. 143 */ 144 public static final String ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS = 145 "ds-soft-delete-requester-ip-address"; 146 147 148 149 /** 150 * The name of the attribute that will be included in a soft-deleted entry to 151 * indicate the time it was converted to a soft-deleted entry. 152 */ 153 public static final String ATTR_SOFT_DELETE_TIMESTAMP = 154 "ds-soft-delete-timestamp"; 155 156 157 158 /** 159 * The name of the auxiliary object class that will be used to mark 160 * soft-deleted entries. 161 */ 162 public static final String OC_SOFT_DELETED_ENTRY = "ds-soft-delete-entry"; 163 164 165 166 /** 167 * The serial version UID for this serializable class. 168 */ 169 private static final long serialVersionUID = -3450703461178674797L; 170 171 172 173 // The time the entry was converted to a soft-deleted entry. 174 private final Date softDeleteTimestamp; 175 176 // The DN held by the entry at the time it was converted to a soft-deleted 177 // entry. 178 private final String softDeleteFromDN; 179 180 // The DN of the user that requested the soft delete operation. 181 private final String softDeleteRequesterDN; 182 183 // The IP address of the client that requested the soft delete operation. 184 private final String softDeleteRequesterIPAddress; 185 186 187 188 /** 189 * Creates a soft-deleted entry from the provided entry. 190 * 191 * @param entry The entry to be processed as a soft-deleted entry. It must 192 * not be {@code null}. 193 * 194 * @throws LDAPException If the provided entry does not represent a valid 195 * soft-deleted entry. 196 */ 197 public SoftDeletedEntry(final Entry entry) 198 throws LDAPException 199 { 200 super(entry); 201 202 if (! entry.hasObjectClass(OC_SOFT_DELETED_ENTRY)) 203 { 204 throw new LDAPException(ResultCode.LOCAL_ERROR, 205 ERR_SOFT_DELETED_ENTRY_MISSING_OC.get(entry.getDN())); 206 } 207 208 softDeleteFromDN = entry.getAttributeValue(ATTR_SOFT_DELETE_FROM_DN); 209 softDeleteTimestamp = 210 entry.getAttributeValueAsDate(ATTR_SOFT_DELETE_TIMESTAMP); 211 softDeleteRequesterDN = 212 entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_DN); 213 softDeleteRequesterIPAddress = 214 entry.getAttributeValue(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS); 215 216 if (softDeleteFromDN == null) 217 { 218 throw new LDAPException(ResultCode.LOCAL_ERROR, 219 ERR_SOFT_DELETED_ENTRY_MISSING_FROM_DN.get(entry.getDN())); 220 } 221 } 222 223 224 225 /** 226 * Retrieves the DN held by the entry at the time it was converted to a 227 * soft-deleted entry. 228 * 229 * @return The DN held by the entry at the time it was converted to a 230 * soft-deleted entry. 231 */ 232 public String getSoftDeleteFromDN() 233 { 234 return softDeleteFromDN; 235 } 236 237 238 239 /** 240 * Retrieves the time that the entry was converted to a soft-deleted entry, 241 * if available. 242 * 243 * @return The time that the entry was converted to a soft-deleted entry, or 244 * {@code null} if this is not available in the entry. 245 */ 246 public Date getSoftDeleteTimestamp() 247 { 248 return softDeleteTimestamp; 249 } 250 251 252 253 /** 254 * Retrieves the DN of the user that requested the soft delete operation, 255 * if available. 256 * 257 * @return The DN of the user that requested the soft delete operation, or 258 * {@code null} if this is not available in the entry. 259 */ 260 public String getSoftDeleteRequesterDN() 261 { 262 return softDeleteRequesterDN; 263 } 264 265 266 267 /** 268 * Retrieves the IP address of the client that requested the soft delete 269 * operation, if available. 270 * 271 * @return The IP address of the client that requested the soft delete 272 * operation, or {@code null} if this is not available in the entry. 273 */ 274 public String getSoftDeleteRequesterIPAddress() 275 { 276 return softDeleteRequesterIPAddress; 277 } 278 279 280 281 /** 282 * Retrieves a copy of the original entry as it appeared before the soft 283 * delete operation was processed. It will have its original DN and all 284 * soft delete metadata attributes and auxiliary object class removed. 285 * 286 * @return A copy of the original entry as it appeared before the soft delete 287 * operation was processed. 288 */ 289 public ReadOnlyEntry getUndeletedEntry() 290 { 291 final Entry e = duplicate(); 292 293 e.setDN(softDeleteFromDN); 294 295 e.removeAttributeValue("objectClass", OC_SOFT_DELETED_ENTRY); 296 e.removeAttribute(ATTR_SOFT_DELETE_FROM_DN); 297 e.removeAttribute(ATTR_SOFT_DELETE_TIMESTAMP); 298 e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_DN); 299 e.removeAttribute(ATTR_SOFT_DELETE_REQUESTER_IP_ADDRESS); 300 301 return new ReadOnlyEntry(e); 302 } 303 304 305 306 /** 307 * Indicates whether the provided entry may be parsed as a valid soft-deleted 308 * entry. 309 * 310 * @param entry The entry to be examined. It must not be {@code null}. 311 * 312 * @return {@code true} if the provided entry contains at least a 313 * ds-soft-delete-entry object class and a ds-soft-delete-from-dn 314 * attribute. 315 */ 316 public static boolean isSoftDeletedEntry(final Entry entry) 317 { 318 return (entry.hasObjectClass(OC_SOFT_DELETED_ENTRY) && 319 entry.hasAttribute(ATTR_SOFT_DELETE_FROM_DN)); 320 } 321}