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 package org.apache.directory.server.factory;
020
021 import java.lang.annotation.Annotation;
022 import java.lang.reflect.Method;
023
024 import org.apache.directory.server.annotations.CreateKdcServer;
025 import org.apache.directory.server.annotations.CreateLdapServer;
026 import org.apache.directory.server.annotations.CreateTransport;
027 import org.apache.directory.server.annotations.SaslMechanism;
028 import org.apache.directory.server.core.DirectoryService;
029 import org.apache.directory.server.i18n.I18n;
030 import org.apache.directory.server.kerberos.kdc.KdcServer;
031 import org.apache.directory.server.ldap.ExtendedOperationHandler;
032 import org.apache.directory.server.ldap.LdapServer;
033 import org.apache.directory.server.ldap.handlers.bind.MechanismHandler;
034 import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmMechanismHandler;
035 import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmProvider;
036 import org.apache.directory.server.protocol.shared.transport.TcpTransport;
037 import org.apache.directory.server.protocol.shared.transport.Transport;
038 import org.apache.directory.server.protocol.shared.transport.UdpTransport;
039 import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
040 import org.apache.mina.util.AvailablePortFinder;
041 import org.junit.runner.Description;
042
043 /**
044 *
045 * Annotation processor for creating LDAP and Kerberos servers.
046 *
047 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
048 * @version $Rev$, $Date$
049 */
050 public class ServerAnnotationProcessor
051 {
052 private static void createTransports( LdapServer ldapServer, CreateTransport[] transportBuilders, int startPort )
053 {
054 if ( transportBuilders.length != 0 )
055 {
056 int createdPort = startPort;
057
058 for ( CreateTransport transportBuilder : transportBuilders )
059 {
060 String protocol = transportBuilder.protocol();
061 int port = transportBuilder.port();
062 int nbThreads = transportBuilder.nbThreads();
063 int backlog = transportBuilder.backlog();
064 String address = transportBuilder.address();
065
066 if ( port == -1 )
067 {
068 port = AvailablePortFinder.getNextAvailable( createdPort );
069 createdPort = port + 1;
070 }
071
072 if ( protocol.equalsIgnoreCase( "LDAP" ) )
073 {
074 Transport ldap = new TcpTransport( address, port, nbThreads, backlog );
075 ldapServer.addTransports( ldap );
076 }
077 else if ( protocol.equalsIgnoreCase( "LDAPS" ) )
078 {
079 Transport ldaps = new TcpTransport( address, port, nbThreads, backlog );
080 ldaps.setEnableSSL( true );
081 ldapServer.addTransports( ldaps );
082 }
083 else
084 {
085 throw new IllegalArgumentException( I18n.err( I18n.ERR_689, protocol ) );
086 }
087 }
088 }
089 else
090 {
091 // Create default LDAP and LDAPS transports
092 int port = AvailablePortFinder.getNextAvailable( 1024 );
093 Transport ldap = new TcpTransport( port );
094 ldapServer.addTransports( ldap );
095
096 port = AvailablePortFinder.getNextAvailable( port );
097 Transport ldaps = new TcpTransport( port );
098 ldaps.setEnableSSL( true );
099 ldapServer.addTransports( ldaps );
100 }
101 }
102
103
104 private static LdapServer createLdapServer( CreateLdapServer createLdapServer, DirectoryService directoryService, int startPort )
105 {
106 if ( createLdapServer != null )
107 {
108 LdapServer ldapServer = new LdapServer();
109
110 ldapServer.setServiceName( createLdapServer.name() );
111
112 // Read the transports
113 createTransports( ldapServer, createLdapServer.transports(), startPort );
114
115 // Associate the DS to this LdapServer
116 ldapServer.setDirectoryService( directoryService );
117
118 ldapServer.setSaslHost( createLdapServer.saslHost() );
119
120 ldapServer.setSaslPrincipal( createLdapServer.saslPrincipal() );
121
122 for( Class<?> extOpClass : createLdapServer.extendedOpHandlers() )
123 {
124 try
125 {
126 ExtendedOperationHandler extOpHandler = ( ExtendedOperationHandler ) extOpClass.newInstance();
127 ldapServer.addExtendedOperationHandler( extOpHandler );
128 }
129 catch( Exception e )
130 {
131 throw new RuntimeException( I18n.err( I18n.ERR_690, extOpClass.getName() ), e );
132 }
133 }
134
135 for( SaslMechanism saslMech : createLdapServer.saslMechanisms() )
136 {
137 try
138 {
139 MechanismHandler handler = ( MechanismHandler ) saslMech.implClass().newInstance();
140 ldapServer.addSaslMechanismHandler( saslMech.name(), handler );
141 }
142 catch( Exception e )
143 {
144 throw new RuntimeException( I18n.err( I18n.ERR_691, saslMech.name(), saslMech.implClass().getName() ), e );
145 }
146 }
147
148 NtlmMechanismHandler ntlmHandler = ( NtlmMechanismHandler ) ldapServer.getSaslMechanismHandlers().get( SupportedSaslMechanisms.NTLM );
149 if( ntlmHandler != null )
150 {
151 Class<?> ntlmProviderClass = createLdapServer.ntlmProvider();
152 // default value is a invalid Object.class
153 if( ( ntlmProviderClass != null ) && ( ntlmProviderClass != Object.class ) )
154 {
155 try
156 {
157 ntlmHandler.setNtlmProvider( ( NtlmProvider ) ntlmProviderClass.newInstance() );
158 }
159 catch( Exception e )
160 {
161 throw new RuntimeException( I18n.err( I18n.ERR_692 ), e );
162 }
163 }
164 }
165
166 // Launch the server
167 try
168 {
169 ldapServer.start();
170 }
171 catch ( Exception e )
172 {
173 e.printStackTrace();
174 }
175
176 return ldapServer;
177 }
178 else
179 {
180 return null;
181 }
182 }
183
184
185 public static LdapServer getLdapServer( DirectoryService directoryService, int startPort ) throws Exception
186 {
187 CreateLdapServer createLdapServer = ( CreateLdapServer ) getAnnotation( CreateLdapServer.class );
188
189 // Ok, we have found a CreateLdapServer annotation. Process it now.
190 return createLdapServer( createLdapServer, directoryService, startPort );
191 }
192
193
194 public static LdapServer getLdapServer( Description description, DirectoryService directoryService, int startPort ) throws Exception
195 {
196 CreateLdapServer createLdapServer = description.getAnnotation( CreateLdapServer.class );
197
198 // Ok, we have found a CreateLdapServer annotation. Process it now.
199 return createLdapServer( createLdapServer, directoryService, startPort );
200 }
201
202 @SuppressWarnings("unchecked")
203 private static Annotation getAnnotation( Class annotationClass ) throws Exception
204 {
205 // Get the caller by inspecting the stackTrace
206 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
207
208 // In Java5 the 0th stacktrace element is: java.lang.Thread.dumpThreads(Native Method)
209 int index = stackTrace[0].getMethodName().equals( "dumpThreads" ) ? 4 : 3;
210
211 // Get the enclosing class
212 Class<?> classCaller = Class.forName( stackTrace[index].getClassName() );
213
214 // Get the current method
215 String methodCaller = stackTrace[index].getMethodName();
216
217 // Check if we have any annotation associated with the method
218 Method[] methods = classCaller.getMethods();
219
220 for ( Method method : methods )
221 {
222 if ( methodCaller.equals( method.getName() ) )
223 {
224 Annotation annotation = method.getAnnotation( annotationClass );
225
226 if ( annotation != null )
227 {
228 return annotation;
229 }
230 }
231 }
232
233 // No : look at the class level
234 return classCaller.getAnnotation( annotationClass );
235 }
236
237
238 public static KdcServer getKdcServer( DirectoryService directoryService, int startPort ) throws Exception
239 {
240 CreateKdcServer createKdcServer = ( CreateKdcServer ) getAnnotation( CreateKdcServer.class );
241
242 return createKdcServer( createKdcServer, directoryService, startPort );
243 }
244
245
246 private static KdcServer createKdcServer( CreateKdcServer createKdcServer, DirectoryService directoryService, int startPort )
247 {
248 if( createKdcServer == null )
249 {
250 return null;
251 }
252
253 KdcServer kdcServer = new KdcServer();
254 kdcServer.setServiceName( createKdcServer.name() );
255 kdcServer.setKdcPrincipal( createKdcServer.kdcPrincipal() );
256 kdcServer.setPrimaryRealm( createKdcServer.primaryRealm() );
257 kdcServer.setMaximumTicketLifetime( createKdcServer.maxTicketLifetime() );
258 kdcServer.setMaximumRenewableLifetime( createKdcServer.maxRenewableLifetime() );
259
260 CreateTransport[] transportBuilders = createKdcServer.transports();
261
262 if( transportBuilders == null )
263 {
264 // create only UDP transport if none specified
265 UdpTransport defaultTransport = new UdpTransport( AvailablePortFinder.getNextAvailable( startPort ) );
266 kdcServer.addTransports( defaultTransport );
267 }
268 else if( transportBuilders.length > 0 )
269 {
270 for( CreateTransport transportBuilder : transportBuilders )
271 {
272 String protocol = transportBuilder.protocol();
273 int port = transportBuilder.port();
274 int nbThreads = transportBuilder.nbThreads();
275 int backlog = transportBuilder.backlog();
276 String address = transportBuilder.address();
277
278 if ( port == -1 )
279 {
280 port = AvailablePortFinder.getNextAvailable( startPort );
281 startPort = port + 1;
282 }
283
284 if ( protocol.equalsIgnoreCase( "TCP" ) )
285 {
286 Transport tcp = new TcpTransport( address, port, nbThreads, backlog );
287 kdcServer.addTransports( tcp );
288 }
289 else if ( protocol.equalsIgnoreCase( "UDP" ) )
290 {
291 UdpTransport udp = new UdpTransport( address, port );
292 kdcServer.addTransports( udp );
293 }
294 else
295 {
296 throw new IllegalArgumentException( I18n.err( I18n.ERR_689, protocol ) );
297 }
298 }
299 }
300
301 kdcServer.setDirectoryService( directoryService );
302
303 // Launch the server
304 try
305 {
306 kdcServer.start();
307 }
308 catch ( Exception e )
309 {
310 e.printStackTrace();
311 }
312
313 return kdcServer;
314 }
315
316
317 public static KdcServer getKdcServer( Description description, DirectoryService directoryService, int startPort ) throws Exception
318 {
319 CreateKdcServer createLdapServer = description.getAnnotation( CreateKdcServer.class );
320
321 return createKdcServer( createLdapServer, directoryService, startPort );
322 }
323
324 }