001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.jndi; 021 022 023 import java.util.Hashtable; 024 025 import javax.naming.Name; 026 import javax.naming.NamingException; 027 import javax.naming.directory.InvalidAttributeIdentifierException; 028 import javax.naming.ldap.Control; 029 import javax.naming.ldap.ExtendedRequest; 030 import javax.naming.ldap.ExtendedResponse; 031 import javax.naming.ldap.LdapContext; 032 import javax.naming.ldap.LdapName; 033 034 import org.apache.directory.server.core.CoreSession; 035 import org.apache.directory.server.core.DirectoryService; 036 import org.apache.directory.server.core.LdapPrincipal; 037 import org.apache.directory.server.core.interceptor.context.CompareOperationContext; 038 import org.apache.directory.server.core.interceptor.context.UnbindOperationContext; 039 import org.apache.directory.server.i18n.I18n; 040 import org.apache.directory.shared.ldap.NotImplementedException; 041 import org.apache.directory.shared.ldap.entry.BinaryValue; 042 import org.apache.directory.shared.ldap.entry.StringValue; 043 import org.apache.directory.shared.ldap.entry.Value; 044 import org.apache.directory.shared.ldap.exception.LdapException; 045 import org.apache.directory.shared.ldap.jndi.JndiUtils; 046 import org.apache.directory.shared.ldap.name.DN; 047 import org.apache.directory.shared.ldap.schema.AttributeType; 048 import org.apache.directory.shared.ldap.util.StringTools; 049 050 051 /** 052 * An implementation of a JNDI LdapContext. 053 * 054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 055 * @version $Rev: 928945 $ 056 */ 057 public class ServerLdapContext extends ServerDirContext implements LdapContext 058 { 059 /** 060 * Creates an instance of an ServerLdapContext. 061 * 062 * @param service the parent service that manages this context 063 * @param env the JNDI environment parameters 064 * @throws NamingException the context cannot be created 065 */ 066 public ServerLdapContext( DirectoryService service, Hashtable<String, Object> env ) throws Exception 067 { 068 super( service, env ); 069 } 070 071 072 /** 073 * Creates a new ServerDirContext with a distinguished name which is used to 074 * set the PROVIDER_URL to the distinguished name for this context. 075 * 076 * @param principal the directory user principal that is propagated 077 * @param dn the distinguished name of this context 078 * @param service the directory service core 079 * @throws NamingException if there are problems instantiating 080 */ 081 public ServerLdapContext( DirectoryService service, LdapPrincipal principal, Name dn ) throws Exception 082 { 083 super( service, principal, dn ); 084 } 085 086 087 public ServerLdapContext( DirectoryService service, CoreSession session, Name bindDn ) throws Exception 088 { 089 super( service, session, bindDn ); 090 } 091 092 093 /** 094 * @see javax.naming.ldap.LdapContext#extendedOperation( 095 * javax.naming.ldap.ExtendedRequest) 096 */ 097 public ExtendedResponse extendedOperation( ExtendedRequest request ) 098 { 099 throw new NotImplementedException(); 100 } 101 102 103 /** 104 * @see javax.naming.ldap.LdapContext#newInstance( 105 * javax.naming.ldap.Control[]) 106 */ 107 public LdapContext newInstance( Control[] requestControls ) throws NamingException 108 { 109 ServerLdapContext ctx = null; 110 111 try 112 { 113 ctx = new ServerLdapContext( getService(), getSession().getEffectivePrincipal(), DN.toName( getDn() ) ); 114 } 115 catch ( Exception e ) 116 { 117 JndiUtils.wrap( e ); 118 } 119 120 ctx.setRequestControls( requestControls ); 121 return ctx; 122 } 123 124 125 /** 126 * @see javax.naming.ldap.LdapContext#reconnect(javax.naming.ldap.Control[]) 127 */ 128 public void reconnect( Control[] connCtls ) throws NamingException 129 { 130 this.connectControls = connCtls; 131 } 132 133 134 /** 135 * @see javax.naming.ldap.LdapContext#getConnectControls() 136 */ 137 public Control[] getConnectControls() throws NamingException 138 { 139 return this.connectControls; 140 } 141 142 143 /** 144 * @see javax.naming.ldap.LdapContext#setRequestControls( 145 * javax.naming.ldap.Control[]) 146 */ 147 public void setRequestControls( Control[] requestControls ) throws NamingException 148 { 149 this.requestControls = requestControls; 150 } 151 152 153 /** 154 * @see javax.naming.ldap.LdapContext#getRequestControls() 155 */ 156 public Control[] getRequestControls() throws NamingException 157 { 158 return requestControls; 159 } 160 161 162 /** 163 * @see javax.naming.ldap.LdapContext#getResponseControls() 164 */ 165 public Control[] getResponseControls() throws NamingException 166 { 167 return responseControls; 168 } 169 170 171 // ------------------------------------------------------------------------ 172 // Additional ApacheDS Specific JNDI Functionality 173 // ------------------------------------------------------------------------ 174 175 /** 176 * Explicitly exposes an LDAP compare operation which JNDI does not 177 * directly provide. All normalization and schema checking etcetera 178 * is handled by this call. 179 * 180 * @param name the name of the entri 181 * @param oid the name or object identifier for the attribute to compare 182 * @param value the value to compare the attribute to 183 * @return true if the entry has the value for the attribute, false otherwise 184 * @throws NamingException if the backing store cannot be accessed, or 185 * permission is not allowed for this operation or the oid is not recognized, 186 * or the attribute is not present in the entry ... you get the picture. 187 */ 188 public boolean compare( DN name, String oid, Object value ) throws NamingException 189 { 190 Value<?> val = null; 191 192 AttributeType attributeType = null; 193 194 try 195 { 196 attributeType = getService().getSchemaManager().lookupAttributeTypeRegistry( oid ); 197 } 198 catch ( LdapException le ) 199 { 200 throw new InvalidAttributeIdentifierException( le.getMessage() ); 201 } 202 203 // make sure we add the request controls to operation 204 if ( attributeType.getSyntax().isHumanReadable() ) 205 { 206 if ( value instanceof String ) 207 { 208 val = new StringValue( attributeType, (String)value ); 209 } 210 else if ( value instanceof byte[] ) 211 { 212 val = new StringValue( attributeType, StringTools.utf8ToString( (byte[])value ) ); 213 } 214 else 215 { 216 throw new NamingException( I18n.err( I18n.ERR_309, oid ) ); 217 } 218 } 219 else 220 { 221 if ( value instanceof String ) 222 { 223 val = new BinaryValue( attributeType, StringTools.getBytesUtf8( (String)value ) ); 224 } 225 else if ( value instanceof byte[] ) 226 { 227 val = new BinaryValue( attributeType, (byte[])value ); 228 } 229 else 230 { 231 throw new NamingException( I18n.err( I18n.ERR_309, oid ) ); 232 } 233 } 234 235 236 CompareOperationContext opCtx = new CompareOperationContext( getSession(), name, oid, val ); 237 opCtx.addRequestControls( JndiUtils.fromJndiControls( requestControls ) ); 238 239 // Inject the Referral flag 240 injectReferralControl( opCtx ); 241 242 // execute operation 243 boolean result = false; 244 try 245 { 246 result = super.getDirectoryService().getOperationManager().compare( opCtx ); 247 } 248 catch ( Exception e ) 249 { 250 JndiUtils.wrap( e ); 251 } 252 253 // extract the response controls from the operation and return 254 responseControls = getResponseControls(); 255 requestControls = EMPTY_CONTROLS; 256 return result; 257 } 258 259 260 /** 261 * Calling this method tunnels an unbind call down into the partition holding 262 * the bindDn. The bind() counter part is not exposed because it is automatically 263 * called when you create a new initial context for a new connection (on wire) or 264 * (programatic) caller. 265 * 266 * @throws NamingException if there are failures encountered while unbinding 267 */ 268 public void ldapUnbind() throws NamingException 269 { 270 UnbindOperationContext opCtx = new UnbindOperationContext( getSession() ); 271 opCtx.addRequestControls( JndiUtils.fromJndiControls( requestControls ) ); 272 273 try 274 { 275 super.getDirectoryService().getOperationManager().unbind( opCtx ); 276 } 277 catch ( Exception e ) 278 { 279 JndiUtils.wrap( e ); 280 } 281 282 responseControls = JndiUtils.toJndiControls( opCtx.getResponseControls() ); 283 requestControls = EMPTY_CONTROLS; 284 } 285 286 287 public ServerContext getRootContext() throws NamingException 288 { 289 ServerContext ctx = null; 290 291 try 292 { 293 ctx = new ServerLdapContext( getService(), getSession().getEffectivePrincipal(), new LdapName( "" ) ); 294 } 295 catch ( Exception e ) 296 { 297 JndiUtils.wrap( e ); 298 } 299 300 return ctx; 301 } 302 }