1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.changepw.protocol;
21
22
23 import java.io.IOException;
24 import java.io.UnsupportedEncodingException;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.net.SocketAddress;
28 import java.net.UnknownHostException;
29
30 import javax.security.auth.kerberos.KerberosPrincipal;
31
32 import junit.framework.TestCase;
33 import org.apache.directory.server.changepw.ChangePasswordServer;
34 import org.apache.directory.server.changepw.io.ChangePasswordDataEncoder;
35 import org.apache.directory.server.changepw.messages.ChangePasswordError;
36 import org.apache.directory.server.changepw.messages.ChangePasswordRequest;
37 import org.apache.directory.server.changepw.value.ChangePasswordData;
38 import org.apache.directory.server.changepw.value.ChangePasswordDataModifier;
39 import org.apache.directory.server.kerberos.shared.KerberosMessageType;
40 import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
41 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
42 import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
43 import org.apache.directory.server.kerberos.shared.crypto.encryption.RandomKeyFactory;
44 import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
45 import org.apache.directory.server.kerberos.shared.messages.ApplicationRequest;
46 import org.apache.directory.server.kerberos.shared.messages.ErrorMessage;
47 import org.apache.directory.server.kerberos.shared.messages.application.PrivateMessage;
48 import org.apache.directory.server.kerberos.shared.messages.components.AuthenticatorModifier;
49 import org.apache.directory.server.kerberos.shared.messages.components.EncKrbPrivPart;
50 import org.apache.directory.server.kerberos.shared.messages.components.EncKrbPrivPartModifier;
51 import org.apache.directory.server.kerberos.shared.messages.components.Ticket;
52 import org.apache.directory.server.kerberos.shared.messages.value.ApOptions;
53 import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
54 import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
55 import org.apache.directory.server.kerberos.shared.messages.value.HostAddress;
56 import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
57 import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName;
58 import org.apache.directory.server.kerberos.shared.messages.value.types.PrincipalNameType;
59 import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
60 import org.apache.directory.server.kerberos.shared.store.TicketFactory;
61 import org.apache.mina.common.IoFilterChain;
62 import org.apache.mina.common.IoHandler;
63 import org.apache.mina.common.IoService;
64 import org.apache.mina.common.IoServiceConfig;
65 import org.apache.mina.common.IoSessionConfig;
66 import org.apache.mina.common.TransportType;
67 import org.apache.mina.common.WriteFuture;
68 import org.apache.mina.common.support.BaseIoSession;
69
70
71
72
73
74
75
76
77 public class ChangepwProtocolHandlerTest extends TestCase
78 {
79
80
81
82
83
84
85
86 private ChangePasswordServer config;
87 private PrincipalStore store;
88 private ChangePasswordProtocolHandler handler;
89 private DummySession session;
90
91 private CipherTextHandler cipherTextHandler = new CipherTextHandler();
92
93
94
95
96
97 public ChangepwProtocolHandlerTest()
98 {
99 config = new ChangePasswordServer();
100 store = new MapPrincipalStoreImpl();
101 handler = new ChangePasswordProtocolHandler( config, store );
102 session = new DummySession();
103 }
104
105
106
107
108
109 public void testProtocolVersionNumber()
110 {
111 ChangePasswordRequest message = new ChangePasswordRequest( ( short ) 2, null, null );
112
113 handler.messageReceived( session, message );
114
115 ChangePasswordError reply = ( ChangePasswordError ) session.getMessage();
116 ErrorMessage error = reply.getErrorMessage();
117 assertEquals( "Protocol version unsupported", 6, error.getErrorCode() );
118 }
119
120
121
122
123
124
125 public void testMissingTicket()
126 {
127 ChangePasswordRequest message = new ChangePasswordRequest( ( short ) 1, null, null );
128
129 handler.messageReceived( session, message );
130
131 ChangePasswordError reply = ( ChangePasswordError ) session.getMessage();
132 ErrorMessage error = reply.getErrorMessage();
133 assertEquals( "Request failed due to an error in authentication processing", 3, error.getErrorCode() );
134 }
135
136
137
138
139
140
141
142
143 public void testInitialFlagRequired() throws Exception
144 {
145 KerberosPrincipal clientPrincipal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
146
147 KerberosPrincipal serverPrincipal = new KerberosPrincipal( "kadmin/changepw@EXAMPLE.COM" );
148 String serverPassword = "secret";
149
150 TicketFactory ticketFactory = new TicketFactory();
151 EncryptionKey serverKey = ticketFactory.getServerKey( serverPrincipal, serverPassword );
152 Ticket serviceTicket = ticketFactory.getTicket( clientPrincipal, serverPrincipal, serverKey );
153
154 EncryptionKey subSessionKey = RandomKeyFactory.getRandomKey( EncryptionType.DES_CBC_MD5 );
155
156 ApOptions apOptions = new ApOptions();
157
158 AuthenticatorModifier modifier = new AuthenticatorModifier();
159 modifier.setVersionNumber( 5 );
160 modifier.setClientRealm( "EXAMPLE.COM" );
161 modifier.setClientName( getPrincipalName( "hnelson" ) );
162 modifier.setClientTime( new KerberosTime() );
163 modifier.setClientMicroSecond( 0 );
164
165 modifier.setSubSessionKey( subSessionKey );
166
167 EncryptedData encryptedAuthenticator = cipherTextHandler.seal( serviceTicket.getEncTicketPart().getSessionKey(), modifier
168 .getAuthenticator(), KeyUsage.NUMBER11 );
169
170 ApplicationRequest apReq = new ApplicationRequest( apOptions, serviceTicket, encryptedAuthenticator );
171
172 String newPassword = "secretsecret";
173
174 PrivateMessage priv = getChangePasswordPrivateMessage( newPassword, subSessionKey );
175
176 ChangePasswordRequest message = new ChangePasswordRequest( ( short ) 1, apReq, priv );
177
178 handler.messageReceived( session, message );
179
180 ChangePasswordError reply = ( ChangePasswordError ) session.getMessage();
181 ErrorMessage error = reply.getErrorMessage();
182 assertEquals( "Initial flag required", 7, error.getErrorCode() );
183
184
185
186
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 public void testSetPassword() throws Exception
220 {
221 KerberosPrincipal clientPrincipal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
222
223 KerberosPrincipal serverPrincipal = new KerberosPrincipal( "kadmin/changepw@EXAMPLE.COM" );
224 String serverPassword = "secret";
225
226 TicketFactory ticketFactory = new TicketFactory();
227 EncryptionKey serverKey = ticketFactory.getServerKey( serverPrincipal, serverPassword );
228 Ticket serviceTicket = ticketFactory.getTicket( clientPrincipal, serverPrincipal, serverKey );
229
230 EncryptionKey subSessionKey = RandomKeyFactory.getRandomKey( EncryptionType.DES_CBC_MD5 );
231
232 ApOptions apOptions = new ApOptions();
233
234 AuthenticatorModifier modifier = new AuthenticatorModifier();
235 modifier.setVersionNumber( 5 );
236 modifier.setClientRealm( "EXAMPLE.COM" );
237 modifier.setClientName( getPrincipalName( "hnelson" ) );
238 modifier.setClientTime( new KerberosTime() );
239 modifier.setClientMicroSecond( 0 );
240
241 EncryptedData encryptedAuthenticator = cipherTextHandler.seal( serverKey, modifier.getAuthenticator(),
242 KeyUsage.NUMBER11 );
243
244 ApplicationRequest apReq = new ApplicationRequest( apOptions, serviceTicket, encryptedAuthenticator );
245
246 String newPassword = "secretsecret";
247
248 PrivateMessage priv = getSetPasswordPrivateMessage( newPassword, subSessionKey, getPrincipalName( "hnelson" ) );
249
250 ChangePasswordRequest message = new ChangePasswordRequest( ( short ) 0xFF80, apReq, priv );
251
252 handler.messageReceived( session, message );
253
254 ChangePasswordError reply = ( ChangePasswordError ) session.getMessage();
255 ErrorMessage error = reply.getErrorMessage();
256 assertEquals( "Protocol version unsupported", 6, error.getErrorCode() );
257 }
258
259
260
261
262
263 private PrivateMessage getChangePasswordPrivateMessage( String newPassword, EncryptionKey subSessionKey )
264 throws UnsupportedEncodingException, KerberosException, UnknownHostException
265 {
266
267 EncKrbPrivPartModifier privPartModifier = new EncKrbPrivPartModifier();
268 privPartModifier.setUserData( newPassword.getBytes( "UTF-8" ) );
269 privPartModifier.setSenderAddress( new HostAddress( InetAddress.getLocalHost() ) );
270 EncKrbPrivPart encReqPrivPart = privPartModifier.getEncKrbPrivPart();
271
272
273 EncryptedData encryptedPrivPart = cipherTextHandler.seal( subSessionKey, encReqPrivPart, KeyUsage.NUMBER13 );
274
275
276 PrivateMessage privateMessage = new PrivateMessage();
277 privateMessage.setProtocolVersionNumber( 5 );
278 privateMessage.setMessageType( KerberosMessageType.ENC_PRIV_PART );
279 privateMessage.setEncryptedPart( encryptedPrivPart );
280
281 return privateMessage;
282 }
283
284
285
286
287
288 private PrivateMessage getSetPasswordPrivateMessage( String newPassword, EncryptionKey subSessionKey,
289 PrincipalName targetPrincipalName ) throws UnsupportedEncodingException, KerberosException,
290 UnknownHostException, IOException
291 {
292
293 EncKrbPrivPartModifier privPartModifier = new EncKrbPrivPartModifier();
294
295 ChangePasswordDataModifier dataModifier = new ChangePasswordDataModifier();
296 dataModifier.setNewPassword( newPassword.getBytes() );
297 dataModifier.setTargetName( targetPrincipalName );
298 dataModifier.setTargetRealm( "EXAMPLE.COM" );
299 ChangePasswordData data = dataModifier.getChangePasswdData();
300
301 ChangePasswordDataEncoder encoder = new ChangePasswordDataEncoder();
302 byte[] dataBytes = encoder.encode( data );
303
304 privPartModifier.setUserData( dataBytes );
305
306 privPartModifier.setSenderAddress( new HostAddress( InetAddress.getLocalHost() ) );
307 EncKrbPrivPart encReqPrivPart = privPartModifier.getEncKrbPrivPart();
308
309
310 EncryptedData encryptedPrivPart = cipherTextHandler.seal( subSessionKey, encReqPrivPart, KeyUsage.NUMBER13 );
311
312
313 PrivateMessage privateMessage = new PrivateMessage();
314 privateMessage.setProtocolVersionNumber( 5 );
315 privateMessage.setMessageType( KerberosMessageType.ENC_PRIV_PART );
316 privateMessage.setEncryptedPart( encryptedPrivPart );
317
318 return privateMessage;
319 }
320
321
322 private PrincipalName getPrincipalName( String name )
323 {
324 PrincipalName principalName = new PrincipalName();
325 principalName.addName( name );
326 principalName.setNameType( PrincipalNameType.KRB_NT_PRINCIPAL );
327
328 return principalName;
329 }
330
331 private static class DummySession extends BaseIoSession
332 {
333 Object message;
334
335
336 @Override
337 public WriteFuture write( Object message )
338 {
339 this.message = message;
340
341 return super.write( message );
342 }
343
344
345 private Object getMessage()
346 {
347 return message;
348 }
349
350
351 protected void updateTrafficMask()
352 {
353
354 }
355
356
357 public IoService getService()
358 {
359 return null;
360 }
361
362
363 public IoHandler getHandler()
364 {
365 return null;
366 }
367
368
369 public IoFilterChain getFilterChain()
370 {
371 return null;
372 }
373
374
375 public TransportType getTransportType()
376 {
377 return null;
378 }
379
380
381 public SocketAddress getRemoteAddress()
382 {
383 return new InetSocketAddress( 10464 );
384 }
385
386
387 public SocketAddress getLocalAddress()
388 {
389 return null;
390 }
391
392
393 public IoSessionConfig getConfig()
394 {
395 return null;
396 }
397
398
399 public int getScheduledWriteRequests()
400 {
401 return 0;
402 }
403
404
405 public SocketAddress getServiceAddress()
406 {
407 return null;
408 }
409
410
411 public IoServiceConfig getServiceConfig()
412 {
413 return null;
414 }
415
416
417 public int getScheduledWriteBytes()
418 {
419 return 0;
420 }
421 }
422 }