001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.controls; 028 029import java.io.IOException; 030import java.util.LinkedList; 031import java.util.List; 032 033import org.forgerock.i18n.LocalizableMessage; 034import org.forgerock.i18n.slf4j.LocalizedLogger; 035import org.forgerock.opendj.io.ASN1; 036import org.forgerock.opendj.io.ASN1Reader; 037import org.forgerock.opendj.io.ASN1Writer; 038import org.forgerock.opendj.ldap.ByteString; 039import org.forgerock.opendj.ldap.ResultCode; 040import org.opends.server.core.DirectoryServer; 041import org.opends.server.types.AttributeType; 042import org.opends.server.types.Control; 043import org.opends.server.types.DN; 044import org.opends.server.types.DirectoryException; 045 046import static org.opends.messages.ProtocolMessages.*; 047import static org.opends.server.util.ServerConstants.*; 048 049/** 050 * This class partially implements the geteffectiverights control as defined 051 * in draft-ietf-ldapext-acl-model-08.txt. The main differences are: 052 * 053 * - The response control is not supported. Instead the dseecompat 054 * geteffectiverights control implementation creates attributes containing 055 * right information strings and adds those attributes to the 056 * entry being returned. The attribute type names are dynamically created; 057 * see the dseecompat's AciGetEffectiveRights class for details. 058 * 059 * - The dseecompat implementation allows additional attribute types 060 * in the request control for which rights information can be returned. 061 * These are known as the specified attribute types. 062 * 063 * The dseecompat request control value is the following: 064 * 065 * <BR> 066 * <PRE> 067 * GetRightsControl ::= SEQUENCE { 068 * authzId authzId 069 * attributes SEQUENCE OF AttributeType 070 * } 071 * 072 * -- Only the "dn:DN form is supported. 073 * 074 * </PRE> 075 * 076 **/ 077public class GetEffectiveRightsRequestControl extends Control 078{ 079 /** 080 * ControlDecoder implementation to decode this control from a ByteString. 081 */ 082 private static final class Decoder 083 implements ControlDecoder<GetEffectiveRightsRequestControl> 084 { 085 /** {@inheritDoc} */ 086 public GetEffectiveRightsRequestControl decode(boolean isCritical, 087 ByteString value) throws DirectoryException 088 { 089 // If the value is null create a GetEffectiveRightsRequestControl 090 // class with null authzDN and attribute list, else try to 091 // decode the value. 092 if (value == null) 093 { 094 return new GetEffectiveRightsRequestControl(isCritical, (DN)null, 095 (List<AttributeType>)null); 096 } 097 else 098 { 099 ASN1Reader reader = ASN1.getReader(value); 100 DN authzDN; 101 List<AttributeType> attrs=null; 102 String authzIDString=""; 103 try { 104 reader.readStartSequence(); 105 authzIDString = reader.readOctetStringAsString(); 106 String lowerAuthzIDString = authzIDString.toLowerCase(); 107 //Make sure authzId starts with "dn:" and is a valid DN. 108 if (lowerAuthzIDString.startsWith("dn:")) 109 { 110 authzDN = DN.valueOf(authzIDString.substring(3)); 111 } 112 else { 113 LocalizableMessage message = INFO_GETEFFECTIVERIGHTS_INVALID_AUTHZID.get( 114 lowerAuthzIDString); 115 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 116 } 117 //There is an sequence containing an attribute list, try to decode it. 118 if(reader.hasNextElement()) { 119 attrs = new LinkedList<>(); 120 reader.readStartSequence(); 121 while(reader.hasNextElement()) { 122 String attrStr = reader.readOctetStringAsString(); 123 attrs.add(DirectoryServer.getAttributeTypeOrDefault(attrStr)); 124 } 125 reader.readEndSequence(); 126 } 127 reader.readEndSequence(); 128 } catch (IOException e) { 129 logger.traceException(e); 130 131 LocalizableMessage message = 132 INFO_GETEFFECTIVERIGHTS_DECODE_ERROR.get(e.getMessage()); 133 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 134 } 135 136 return new GetEffectiveRightsRequestControl(isCritical, 137 authzDN, attrs); 138 } 139 } 140 141 public String getOID() 142 { 143 return OID_GET_EFFECTIVE_RIGHTS; 144 } 145 } 146 147 /** 148 * The Control Decoder that can be used to decode this control. 149 */ 150 public static final ControlDecoder<GetEffectiveRightsRequestControl> DECODER = 151 new Decoder(); 152 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 153 154 /** The DN representing the authzId. May be null. */ 155 private DN authzDN; 156 157 /** The raw DN representing the authzId. May be null. */ 158 private String rawAuthzDN; 159 160 /** The list of additional attribute types to return rights for. May be null. */ 161 private List<AttributeType> attrs; 162 163 /** The raw DN representing the authzId. May be null. */ 164 private List<String> rawAttrs; 165 166 /** 167 * Create a new geteffectiverights control with the specified authzDN and 168 * an attribute list. 169 * 170 * @param authzDN The authzDN. 171 * 172 * @param attrs The list of additional attributes to be returned. 173 */ 174 public GetEffectiveRightsRequestControl(DN authzDN, 175 List<AttributeType> attrs) { 176 this(true, authzDN, attrs); 177 } 178 179 /** 180 * Create a new geteffectiverights control with the specified authzDN and 181 * an attribute list. 182 * 183 * @param isCritical Indicates whether this control should be 184 * considered critical in processing the 185 * request. 186 * @param authzDN The authzDN. 187 * @param attrs The list of additional attributes to be returned. 188 */ 189 public GetEffectiveRightsRequestControl(boolean isCritical, DN authzDN, 190 List<AttributeType> attrs) { 191 super(OID_GET_EFFECTIVE_RIGHTS, isCritical); 192 this.authzDN=authzDN; 193 this.attrs=attrs; 194 } 195 196 /** 197 * Create a new geteffectiverights control with the specified raw 198 * authzDN and an attribute list. 199 * 200 * @param isCritical Indicates whether this control should be 201 * considered critical in processing the 202 * request. 203 * @param authzDN The authzDN. 204 * @param attrs The list of additional attributes to be returned. 205 */ 206 public GetEffectiveRightsRequestControl(boolean isCritical, 207 String authzDN, 208 List<String> attrs) 209 { 210 super(OID_GET_EFFECTIVE_RIGHTS, isCritical); 211 this.rawAuthzDN=authzDN; 212 this.rawAttrs=attrs; 213 } 214 215 /** 216 * Writes this control's value to an ASN.1 writer. The value (if any) must be 217 * written as an ASN1OctetString. 218 * 219 * @param writer The ASN.1 output stream to write to. 220 * @throws IOException If a problem occurs while writing to the stream. 221 */ 222 @Override 223 public void writeValue(ASN1Writer writer) throws IOException { 224 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 225 226 writer.writeStartSequence(); 227 if(authzDN != null) 228 { 229 writer.writeOctetString("dn:" + authzDN); 230 } 231 else if(rawAuthzDN != null) 232 { 233 writer.writeOctetString("dn:" + rawAuthzDN); 234 } 235 236 if(attrs != null) 237 { 238 writer.writeStartSequence(); 239 for(AttributeType attr : attrs) 240 { 241 writer.writeOctetString(attr.getNameOrOID()); 242 } 243 writer.writeEndSequence(); 244 } 245 else if(rawAttrs != null) 246 { 247 writer.writeStartSequence(); 248 for(String attr : rawAttrs) 249 { 250 writer.writeOctetString(attr); 251 } 252 writer.writeEndSequence(); 253 } 254 writer.writeEndSequence(); 255 256 writer.writeEndSequence(); 257 } 258 259 /** 260 * Return the authzDN parsed from the control. 261 * 262 * @return The DN representing the authzId. 263 */ 264 public DN getAuthzDN () { 265 return authzDN; 266 // TODO: what if rawAuthzDN is not null? 267 } 268 269 /** 270 * Return the requested additional attributes parsed from the control. Known 271 * as the specified attributes. 272 * 273 * @return The list containing any additional attributes to return rights 274 * about. 275 */ 276 public List<AttributeType> getAttributes() { 277 return attrs; 278 } 279}