1 /* 2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jndi.ldap; 27 28 import java.io.IOException; 29 import java.util.Hashtable; 30 import java.util.Vector; 31 import javax.naming.*; 32 import javax.naming.directory.*; 33 34 /** 35 * This subclass is used by LDAP to implement the schema calls. 36 * Basically, it keeps track of which context it is an attribute of 37 * so it can get the schema for that cotnext. 38 * 39 * @author Jon Ruiz 40 */ 41 final class LdapAttribute extends BasicAttribute { 42 43 static final long serialVersionUID = -4288716561020779584L; 44 45 private transient DirContext baseCtx = null; 46 private Name rdn = new CompositeName(); 47 48 // these two are used to reconstruct the baseCtx if this attribute has 49 // been serialized ( 50 private String baseCtxURL; 51 private Hashtable<String, ? super String> baseCtxEnv; 52 53 @SuppressWarnings("unchecked") // clone() 54 public Object clone() { 55 LdapAttribute attr = new LdapAttribute(this.attrID, baseCtx, rdn); 56 attr.values = (Vector<Object>)values.clone(); 57 return attr; 58 } 59 60 /** 61 * Adds a new value to this attribute. 62 * 63 * @param attrVal The value to be added. If null, a null value is added to 64 * the attribute. 65 * @return true Always returns true. 66 */ 67 public boolean add(Object attrVal) { 68 // LDAP attributes don't contain duplicate values so there's no need 69 // to check if the value already exists before adding it. 70 values.addElement(attrVal); 71 return true; 72 } 73 74 /** 75 * Constructs a new instance of an attribute. 76 * 77 * @param id The attribute's id. It cannot be null. 78 */ 79 LdapAttribute(String id) { 80 super(id); 81 } 82 83 /** 84 * Constructs a new instance of an attribute. 85 * 86 * @param id The attribute's id. It cannot be null. 87 * @param baseCtx the baseCtx object of this attribute 88 * @param rdn the RDN of the entry (relative to baseCtx) 89 */ 90 private LdapAttribute(String id, DirContext baseCtx, Name rdn) { 91 super(id); 92 this.baseCtx = baseCtx; 93 this.rdn = rdn; 94 } 95 96 /** 97 * Sets the baseCtx and rdn used to find the attribute's schema 98 * Used by LdapCtx.setParents(). 99 */ 100 void setParent(DirContext baseCtx, Name rdn) { 101 this.baseCtx = baseCtx; 102 this.rdn = rdn; 103 } 104 105 /** 106 * returns the ctx this attribute came from. This call allows 107 * LDAPAttribute to be serializable. 'baseCtx' is transient so if 108 * it is null, the `baseCtxURL` is used to reconstruct the context 109 * to which calls are made. 110 */ 111 private DirContext getBaseCtx() throws NamingException { 112 if(baseCtx == null) { 113 if (baseCtxEnv == null) { 114 baseCtxEnv = new Hashtable<String, String>(3); 115 } 116 baseCtxEnv.put(Context.INITIAL_CONTEXT_FACTORY, 117 "com.sun.jndi.ldap.LdapCtxFactory"); 118 baseCtxEnv.put(Context.PROVIDER_URL,baseCtxURL); 119 baseCtx = (new InitialDirContext(baseCtxEnv)); 120 } 121 return baseCtx; 122 } 123 124 /** 125 * This is called when the object is serialized. It is 126 * overridden so that the appropriate class variables can be set 127 * to re-construct the baseCtx when deserialized. Setting these 128 * variables is costly, so it is only done if the object 129 * is actually serialized. 130 */ 131 private void writeObject(java.io.ObjectOutputStream out) 132 throws IOException { 133 134 // setup internal state 135 this.setBaseCtxInfo(); 136 137 // let the ObjectOutpurStream do the real work of serialization 138 out.defaultWriteObject(); 139 } 140 141 /** 142 * sets the information needed to reconstruct the baseCtx if 143 * we are serialized. This must be called _before_ the object is 144 * serialized!!! 145 */ 146 @SuppressWarnings("unchecked") // clone() 147 private void setBaseCtxInfo() { 148 Hashtable<String, Object> realEnv = null; 149 Hashtable<String, Object> secureEnv = null; 150 151 if (baseCtx != null) { 152 realEnv = ((LdapCtx)baseCtx).envprops; 153 this.baseCtxURL = ((LdapCtx)baseCtx).getURL(); 154 } 155 156 if(realEnv != null && realEnv.size() > 0 ) { 157 // remove any security credentials - otherwise the serialized form 158 // would store them in the clear 159 for (String key : realEnv.keySet()){ 160 if (key.indexOf("security") != -1 ) { 161 162 //if we need to remove props, we must do it to a clone 163 //of the environment. cloning is expensive, so we only do 164 //it if we have to. 165 if(secureEnv == null) { 166 secureEnv = (Hashtable<String, Object>)realEnv.clone(); 167 } 168 secureEnv.remove(key); 169 } 170 } 171 } 172 173 // set baseCtxEnv depending on whether we removed props or not 174 this.baseCtxEnv = (secureEnv == null ? realEnv : secureEnv); 175 } 176 177 /** 178 * Retrieves the syntax definition associated with this attribute. 179 * @return This attribute's syntax definition. 180 */ 181 public DirContext getAttributeSyntaxDefinition() throws NamingException { 182 // get the syntax id from the attribute def 183 DirContext schema = getBaseCtx().getSchema(rdn); 184 DirContext attrDef = (DirContext)schema.lookup( 185 LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID()); 186 187 Attribute syntaxAttr = attrDef.getAttributes("").get("SYNTAX"); 188 189 if(syntaxAttr == null || syntaxAttr.size() == 0) { 190 throw new NameNotFoundException( 191 getID() + " does not have a syntax associated with it"); 192 } 193 194 String syntaxName = (String)syntaxAttr.get(); 195 196 // look in the schema tree for the syntax definition 197 return (DirContext)schema.lookup( 198 LdapSchemaParser.SYNTAX_DEFINITION_NAME + "/" + syntaxName); 199 } 200 201 /** 202 * Retrieves this attribute's schema definition. 203 * 204 * @return This attribute's schema definition. 205 */ 206 public DirContext getAttributeDefinition() throws NamingException { 207 DirContext schema = getBaseCtx().getSchema(rdn); 208 209 return (DirContext)schema.lookup( 210 LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID()); 211 } 212 }