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