View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.jndi;
18  
19  
20  import java.io.IOException;
21  import java.net.InetSocketAddress;
22  import java.util.Hashtable;
23  import java.util.Properties;
24  import java.util.Iterator;
25  
26  import javax.naming.Context;
27  import javax.naming.NamingException;
28  import javax.naming.ldap.InitialLdapContext;
29  import javax.naming.ldap.Control;
30  
31  import org.apache.ldap.common.exception.LdapConfigurationException;
32  import org.apache.ldap.common.name.LdapName;
33  import org.apache.ldap.common.util.PropertiesUtils;
34  import org.apache.ldap.server.protocol.LdapProtocolProvider;
35  import org.apache.mina.common.TransportType;
36  import org.apache.mina.registry.Service;
37  import org.apache.mina.registry.ServiceRegistry;
38  import org.apache.mina.registry.SimpleServiceRegistry;
39  import org.apache.kerberos.service.KdcConfiguration;
40  import org.apache.kerberos.protocol.KerberosProtocolProvider;
41  import org.apache.kerberos.store.PrincipalStore;
42  import org.apache.kerberos.store.JndiPrincipalStoreImpl;
43  
44  
45  /***
46   * Adds additional bootstrapping for server socket listeners when firing
47   * up the server.
48   *
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   * @version $Rev: 168482 $
51   * @see javax.naming.spi.InitialContextFactory
52   */
53  public class ServerContextFactory extends CoreContextFactory
54  {
55      /*** the default LDAP port to use */
56      private static final int LDAP_PORT = 389;
57  
58      private static final ServiceRegistry DEFAULT_MINA_REGISTRY;
59      
60      private static Service ldapService;
61  
62      private static Service kerberosService;
63  
64      private static ServiceRegistry minaRegistry;
65  
66  
67      static
68      {
69          ServiceRegistry tmp = null;
70  
71          try
72          {
73              tmp = new SimpleServiceRegistry();
74          }
75          catch( IOException e )
76          {
77              e.printStackTrace();
78          }
79          
80          DEFAULT_MINA_REGISTRY = tmp;
81      }
82  
83      // ------------------------------------------------------------------------
84      // Members
85      // ------------------------------------------------------------------------
86  
87  
88      /***
89       * Checks first for a shutdown operation and if so stops the server.  Otherwise
90       * it initializes the networking subsystem starting up the mina registery and
91       * other protocol provider services if enabled including the LDAP provider.
92       *
93       * @param env the JNDI environment parameters
94       * @return the new LDAP context to be wrapped by InitialContext
95       * @throws NamingException if there are problems starting or stopping the server
96       */
97      public Context getInitialContext( Hashtable env ) throws NamingException
98      {
99          Context ctx = null;
100 
101         if ( env.containsKey( EnvKeys.SHUTDOWN ) )
102         {
103             if ( this.provider == null )
104             {
105                 return new DeadContext();
106             }
107 
108             try
109             {
110                 this.provider.shutdown();
111 
112                 if ( minaRegistry != null )
113                 {
114                     if ( ldapService != null )
115                     {
116                         minaRegistry.unbind( ldapService );
117 
118                         ldapService = null;
119                     }
120 
121                     if ( kerberosService != null )
122                     {
123                         minaRegistry.unbind( kerberosService );
124 
125                         kerberosService = null;
126                     }
127                 }
128             }
129             catch( NamingException ne )
130             {
131                 throw ne;
132             }
133             catch( Throwable t )
134             {
135                 NamingException ne = new NamingException( "Failed to shutdown." );
136 
137                 ne.setRootCause( t );
138 
139                 throw ne;
140             }
141             finally
142             {
143                 ctx = new DeadContext();
144 
145                 provider = null;
146 
147                 initialEnv = null;
148             }
149 
150             return ctx;
151         }
152 
153         ctx = super.getInitialContext( env );
154 
155         // fire up the front end if we have not explicitly disabled it
156 
157         if ( initialEnv != null && ! initialEnv.containsKey( EnvKeys.DISABLE_PROTOCOL ) )
158         {
159             setupRegistry();
160 
161             startLdapProtocol();
162 
163             if ( initialEnv.containsKey( EnvKeys.ENABLE_KERBEROS ) )
164             {
165                 startKerberosProtocol();
166             }
167         }
168 
169         return ctx;
170     }
171 
172 
173     /***
174      * Starts up the MINA registry so various protocol providers can be started.
175      *
176      * @throws NamingException if there is a problem initializing the registry
177      */
178     private void setupRegistry() throws NamingException
179     {
180         ServiceRegistry registry = null;
181 
182         if ( initialEnv.containsKey( EnvKeys.PASSTHRU ) )
183         {
184             registry = ( ServiceRegistry ) initialEnv.get( EnvKeys.PASSTHRU );
185 
186             if ( registry != null )
187             {
188                 initialEnv.put( EnvKeys.PASSTHRU, "Handoff Succeeded!" );
189             }
190         }
191 
192         if( DEFAULT_MINA_REGISTRY == null )
193         {
194             throw new NamingException( "Default MINA service registry is not available." );
195         }
196 
197         if( registry == null )
198         {
199             registry = DEFAULT_MINA_REGISTRY;
200         }
201 
202         minaRegistry = registry;
203     }
204 
205 
206     /***
207      * Starts the Kerberos protocol provider which is backed by the LDAP store.
208      *
209      * @throws NamingException if there are problems starting up the Kerberos provider
210      */
211     private void startKerberosProtocol() throws NamingException
212     {
213         /*
214          * Looks like KdcConfiguration takes properties and we use Hashtable for JNDI
215          * so I'm copying over the String based properties into a new Properties obj.
216          */
217 
218         Properties props = new Properties();
219 
220         Iterator list = initialEnv.keySet().iterator();
221 
222         while ( list.hasNext() )
223         {
224             String key = ( String ) list.next();
225 
226             if ( initialEnv.get( key ) instanceof String )
227             {
228                 props.setProperty( key, ( String ) initialEnv.get( key ) );
229             }
230         }
231 
232         KdcConfiguration config = new KdcConfiguration( props );
233 
234         int port = PropertiesUtils.get( initialEnv, KdcConfiguration.KERBEROS_PORT_KEY, KdcConfiguration.DEFAULT_KERBEROS_PORT );
235 
236         Service service= new Service( "kerberos", TransportType.DATAGRAM, new InetSocketAddress( port ) );
237 
238         InitialLdapContext ctx = new InitialLdapContext( initialEnv, new Control[]{} );
239 
240         Object baseStr = initialEnv.get( JndiPrincipalStoreImpl.KDC_STORE_SEARCHBASE );
241 
242         if ( baseStr == null )
243         {
244             throw new LdapConfigurationException( "Trying to start kerberos service without setting " + JndiPrincipalStoreImpl.KDC_STORE_SEARCHBASE );
245         }
246 
247         LdapName base = new LdapName( ( String ) baseStr );
248 
249         PrincipalStore store = new JndiPrincipalStoreImpl( ctx, base );
250 
251         try
252         {
253             minaRegistry.bind( service, new KerberosProtocolProvider( config, store ) );
254 
255             kerberosService = service;
256         }
257         catch ( IOException e )
258         {
259             e.printStackTrace();
260         }
261     }
262 
263 
264     /***
265      * Starts up the LDAP protocol provider to service LDAP requests
266      *
267      * @throws NamingException if there are problems starting the LDAP provider
268      */
269     private void startLdapProtocol() throws NamingException
270     {
271         int port = PropertiesUtils.get( initialEnv, EnvKeys.LDAP_PORT, LDAP_PORT );
272 
273         Service service = new Service( "ldap", TransportType.SOCKET, new InetSocketAddress( port ) );
274 
275         try
276         {
277             minaRegistry.bind( service, new LdapProtocolProvider( ( Hashtable ) initialEnv.clone() ) );
278 
279             ldapService = service;
280         }
281         catch ( IOException e )
282         {
283             String msg = "Failed to bind the LDAP protocol service to the service registry: " + service;
284 
285             LdapConfigurationException lce = new LdapConfigurationException( msg );
286 
287             lce.setRootCause( e );
288 
289             throw lce;
290         }
291     }
292 }