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.Iterator;
24  import java.util.Properties;
25  
26  import javax.naming.NamingException;
27  import javax.naming.Context;
28  import javax.naming.directory.DirContext;
29  import javax.naming.ldap.Control;
30  import javax.naming.ldap.InitialLdapContext;
31  import javax.naming.ldap.LdapContext;
32  
33  import org.apache.kerberos.protocol.KerberosProtocolProvider;
34  import org.apache.kerberos.service.KdcConfiguration;
35  import org.apache.kerberos.store.JndiPrincipalStoreImpl;
36  import org.apache.kerberos.store.PrincipalStore;
37  import org.apache.kerberos.sam.SamSubsystem;
38  import org.apache.ldap.common.exception.LdapConfigurationException;
39  import org.apache.ldap.common.name.LdapName;
40  import org.apache.ldap.common.util.PropertiesUtils;
41  import org.apache.ldap.common.util.NamespaceTools;
42  import org.apache.ldap.server.configuration.ServerStartupConfiguration;
43  import org.apache.ldap.server.protocol.LdapProtocolProvider;
44  import org.apache.mina.common.TransportType;
45  import org.apache.mina.registry.Service;
46  import org.apache.mina.registry.ServiceRegistry;
47  
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  
52  /***
53   * Adds additional bootstrapping for server socket listeners when firing
54   * up the server.
55   *
56   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
57   * @version $Rev: 264732 $
58   * @see javax.naming.spi.InitialContextFactory
59   */
60  public class ServerContextFactory extends CoreContextFactory
61  {
62      private static Logger log = LoggerFactory.getLogger( ServerContextFactory.class.getName() );
63      private static Service ldapService;
64      private static Service kerberosService;
65      private static ServiceRegistry minaRegistry;
66  
67  
68      protected ServiceRegistry getMinaRegistry()
69      {
70          return minaRegistry;
71      }
72  
73      public void afterShutdown( ContextFactoryService service )
74      {
75          if ( minaRegistry != null )
76          {
77              if ( ldapService != null )
78              {
79                  minaRegistry.unbind( ldapService );
80                  if ( log.isInfoEnabled() )
81                  {
82                      log.info( "Unbind of LDAP Service complete: " + ldapService );
83                  }
84                  ldapService = null;
85              }
86  
87              if ( kerberosService != null )
88              {
89                  minaRegistry.unbind( kerberosService );
90                  if ( log.isInfoEnabled() )
91                  {
92                      log.info( "Unbind of KRB5 Service complete: " + kerberosService );
93                  }
94                  kerberosService = null;
95              }
96          }
97      }
98      
99      public void afterStartup( ContextFactoryService service ) throws NamingException
100     {
101         ServerStartupConfiguration cfg =
102             ( ServerStartupConfiguration ) service.getConfiguration().getStartupConfiguration();
103         Hashtable env = service.getConfiguration().getEnvironment();
104 
105         if ( cfg.isEnableNetworking() )
106         {
107             setupRegistry( cfg );
108             startLdapProtocol( cfg, env );
109 
110             if ( cfg.isEnableKerberos() )
111             {
112                 startKerberosProtocol( env );
113             }
114         }
115     }
116 
117     /***
118      * Starts up the MINA registry so various protocol providers can be started.
119      */
120     private void setupRegistry( ServerStartupConfiguration cfg )
121     {
122         minaRegistry = cfg.getMinaServiceRegistry();
123     }
124 
125 
126     /***
127      * Starts the Kerberos protocol provider which is backed by the LDAP store.
128      *
129      * @throws NamingException if there are problems starting up the Kerberos provider
130      */
131     private void startKerberosProtocol( Hashtable env ) throws NamingException
132     {
133         /*
134          * Looks like KdcConfiguration takes properties and we use Hashtable for JNDI
135          * so I'm copying over the String based properties into a new Properties obj.
136          */
137         Properties props = new Properties();
138         Iterator list = env.keySet().iterator();
139         while ( list.hasNext() )
140         {
141             String key = ( String ) list.next();
142 
143             if ( env.get( key ) instanceof String )
144             {
145                 props.setProperty( key, ( String ) env.get( key ) );
146             }
147         }
148 
149         // construct the configuration, get the port, create the service, and prepare kdc objects
150         KdcConfiguration config = new KdcConfiguration( props );
151         int port = PropertiesUtils.get( env, KdcConfiguration.KERBEROS_PORT_KEY, KdcConfiguration.DEFAULT_KERBEROS_PORT );
152         Service service= new Service( "kerberos", TransportType.DATAGRAM, new InetSocketAddress( port ) );
153         LdapContext ctx = getBaseRealmContext( config, env );
154         PrincipalStore store = new JndiPrincipalStoreImpl( ctx, new LdapName( "ou=Users" ) );
155         SamSubsystem.getInstance().setUserContext( ( DirContext ) ctx, "ou=Users" );
156 
157         try
158         {
159             minaRegistry.bind( service, new KerberosProtocolProvider( config, store ) );
160             kerberosService = service;
161             if ( log.isInfoEnabled() )
162             {
163                 log.info( "Successful bind of KRB5 Service completed: " + kerberosService );
164             }
165         }
166         catch ( IOException e )
167         {
168             log.error( "Could not start the kerberos service on port " +
169                     KdcConfiguration.DEFAULT_KERBEROS_PORT, e );
170         }
171     }
172 
173 
174     /***
175      * Maps a Kerberos Realm name to a position within the DIT.  The primary realm of
176      * the KDC will use this area for configuration and for storing user entries.
177      *
178      * @param config the KDC's configuration
179      * @param env the JNDI environment properties
180      * @return the base context for the primary realm of the KDC
181      * @throws NamingException
182      */
183     private LdapContext getBaseRealmContext( KdcConfiguration config, Hashtable env ) throws NamingException
184     {
185         Hashtable cloned = ( Hashtable ) env.clone();
186         String dn = NamespaceTools.inferLdapName( config.getPrimaryRealm() );
187         cloned.put( Context.PROVIDER_URL, dn );
188 
189         if ( log.isInfoEnabled() )
190         {
191             log.info( "Getting initial context for realm base at " + dn + " for " + config.getPrimaryRealm() );
192         }
193 
194         return new InitialLdapContext( cloned, new Control[]{} );
195     }
196 
197 
198     /***
199      * Starts up the LDAP protocol provider to service LDAP requests
200      *
201      * @throws NamingException if there are problems starting the LDAP provider
202      */
203     private void startLdapProtocol( ServerStartupConfiguration cfg, Hashtable env ) throws NamingException
204     {
205         int port = cfg.getLdapPort();
206         Service service = new Service( "ldap", TransportType.SOCKET, new InetSocketAddress( port ) );
207 
208         try
209         {
210             minaRegistry.bind( service, new LdapProtocolProvider( ( Hashtable ) env.clone() ) );
211             ldapService = service;
212             if ( log.isInfoEnabled() )
213             {
214                 log.info( "Successful bind of LDAP Service completed: " + ldapService );
215             }
216         }
217         catch ( IOException e )
218         {
219             String msg = "Failed to bind the LDAP protocol service to the service registry: " + service;
220             LdapConfigurationException lce = new LdapConfigurationException( msg );
221             lce.setRootCause( e );
222             log.error( msg, e );
223             throw lce;
224         }
225     }
226 }