~ifolder-dev/simias/trunk-packaging

« back to all changes in this revision

Viewing changes to src/server/Simias.ADLdapProvider/.svn/text-base/ADLdapSync.cs.svn-base

  • Committer: Jorge O. Castro
  • Date: 2007-12-03 06:56:46 UTC
  • Revision ID: jorge@ubuntu.com-20071203065646-mupcnjcwgm5mnhyt
* Remove a bunch of .svn directories we no longer need.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
 |
3
 
 | Copyright (c) 2007 Novell, Inc.
4
 
 | All Rights Reserved.
5
 
 |
6
 
 | This program is free software; you can redistribute it and/or
7
 
 | modify it under the terms of version 2 of the GNU General Public License as
8
 
 | published by the Free Software Foundation.
9
 
 |
10
 
 | This program is distributed in the hope that it will be useful,
11
 
 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 | GNU General Public License for more details.
14
 
 |
15
 
 | You should have received a copy of the GNU General Public License
16
 
 | along with this program; if not, contact Novell, Inc.
17
 
 |
18
 
 | To contact Novell about this file by physical or electronic mail,
19
 
 | you may find current contact information at www.novell.com
20
 
 |
21
 
 | Author: Bruce Getter <bgetter@novell.com>
22
 
 |***************************************************************************/
23
 
 
24
 
using System;
25
 
 
26
 
using Novell.Directory.Ldap;
27
 
using Novell.Directory.Ldap.Utilclass;
28
 
 
29
 
using Simias;
30
 
using Simias.LdapProvider;
31
 
using Simias.Storage;
32
 
 
33
 
namespace Simias.ADLdapProvider
34
 
{
35
 
        /// <summary>
36
 
        /// Service class used to get an execution context
37
 
        /// so we can register ourselves with the external
38
 
        /// sync container
39
 
        /// </summary>
40
 
        class ADSync : Simias.IIdentitySyncProvider
41
 
        {
42
 
                #region Class Members
43
 
                private readonly string name = "Active Directory LDAP Synchronization";
44
 
                private readonly string description = "Active Directory LDAP Synchronization provider to synchronize identities from Active Directory to a simias domain";
45
 
                private bool abort = false;
46
 
                
47
 
                private Simias.LdapProvider.Status syncStatus;
48
 
                private static LdapSettings ldapSettings;
49
 
                private Exception syncException;
50
 
 
51
 
                private Store store = null;
52
 
                private Domain domain = null;
53
 
                
54
 
                private LdapConnection conn = null;
55
 
                private Simias.IdentitySync.State state = null;
56
 
                
57
 
                /// <summary>
58
 
                /// Used to log messages.
59
 
                /// </summary>
60
 
                private static readonly ISimiasLog log = 
61
 
                        SimiasLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
62
 
                #endregion
63
 
                
64
 
                #region Properties
65
 
                /// <summary>
66
 
                /// Gets the name of the provider.
67
 
                /// </summary>
68
 
                public string Name { get{ return name; } }
69
 
 
70
 
                /// <summary>
71
 
                /// Gets the description of the provider.
72
 
                /// </summary>
73
 
                public string Description { get{ return description; } }
74
 
                #endregion
75
 
                
76
 
                #region Private Methods
77
 
                
78
 
                private void ProcessSearchObjects( LdapConnection conn, LdapSettings settings )
79
 
                {
80
 
                        foreach ( string searchContext in settings.SearchContexts )
81
 
                        {
82
 
                                string[] searchAttributes = { "objectClass" };
83
 
 
84
 
                                log.Debug( "SearchObject: " + searchContext );
85
 
 
86
 
                                try
87
 
                                {
88
 
                                        LdapEntry ldapEntry = conn.Read( searchContext, searchAttributes );
89
 
                                        LdapAttribute attrObjectClass = ldapEntry.getAttribute( "objectClass" );
90
 
                                        String[] values = attrObjectClass.StringValueArray;
91
 
 
92
 
                                        if ( IsUser( values ) == true )
93
 
                                        {
94
 
                                                // Process SearchDN as 
95
 
                                                log.Debug( "Processing User Object..." );
96
 
                                                ProcessSearchUser( conn, searchContext );
97
 
                                        }
98
 
                                        else if ( IsGroup( values ) == true )
99
 
                                        {
100
 
                                                // Process SearchDN as 
101
 
                                                log.Debug( "Processing Group Object..." );
102
 
                                                ProcessSearchGroup( conn, searchContext );
103
 
                                        }
104
 
                                        else if ( IsContainer( values ) == true )
105
 
                                        {
106
 
                                                // Process SearchDN as Container
107
 
                                                log.Debug( "Processing Container Object..." );
108
 
                                                ProcessSearchContainer( conn, searchContext );
109
 
                                        }
110
 
                                        else
111
 
                                        {
112
 
                                                log.Debug( "Invalid objectClass: " + values[0] );
113
 
                                                log.Debug( attrObjectClass.ToString() );
114
 
                                        }
115
 
                                }
116
 
                                catch( SimiasShutdownException s )
117
 
                                {
118
 
                                        log.Error( s.Message );
119
 
                                        throw s;
120
 
                                }
121
 
                                catch ( LdapException e )
122
 
                                {
123
 
                                        log.Error( e.LdapErrorMessage );
124
 
                                        log.Error( e.StackTrace );
125
 
                                }
126
 
                                catch ( Exception e )
127
 
                                {
128
 
                                        log.Error( e.Message );
129
 
                                        log.Error( e.StackTrace );
130
 
                                }
131
 
                        }
132
 
                }
133
 
                
134
 
                private string BuildGuidFilter( string guid )
135
 
                {
136
 
                        Guid cGuid = new Guid( guid );
137
 
                        byte[] bGuid = cGuid.ToByteArray();
138
 
 
139
 
                        string guidFilter = "(objectGUID=";
140
 
                        string tmp;
141
 
 
142
 
                        // The CSharpLdap SDK expects each byte to
143
 
                        // be zero padded else an exception is thrown
144
 
                        for( int i = 0; i < 16; i++ )
145
 
                        {
146
 
                                guidFilter += "\\";
147
 
                                tmp = Convert.ToString( bGuid[i], 16 );
148
 
                                if ( tmp.Length == 1 )
149
 
                                {
150
 
                                        guidFilter += "0";
151
 
                                }
152
 
                                guidFilter += tmp;
153
 
                        }
154
 
 
155
 
                        guidFilter += ")";
156
 
                        return guidFilter;
157
 
                }
158
 
 
159
 
                private string GetLdapGuid( LdapEntry entry )
160
 
                {
161
 
                        string ldapGuid = null;
162
 
 
163
 
                        try
164
 
                        {
165
 
                                LdapAttribute guidAttr = entry.getAttribute( "objectGUID" );
166
 
                                if ( guidAttr != null && guidAttr.StringValue.Length != 0 )
167
 
                                {
168
 
                                        byte[] bGuid = new byte[8];
169
 
                                        for( int i = 0; i < 8; i++ )
170
 
                                        {
171
 
                                                bGuid[i] = (byte) guidAttr.ByteValue[i];
172
 
                                        }
173
 
 
174
 
                                        Guid cGuid = 
175
 
                                                new Guid(
176
 
                                                BitConverter.ToInt32( bGuid, 0 ),
177
 
                                                BitConverter.ToInt16( bGuid, 4 ),
178
 
                                                BitConverter.ToInt16( bGuid, 6 ),
179
 
                                                (byte) guidAttr.ByteValue[8], 
180
 
                                                (byte) guidAttr.ByteValue[9],
181
 
                                                (byte) guidAttr.ByteValue[10],
182
 
                                                (byte) guidAttr.ByteValue[11],
183
 
                                                (byte) guidAttr.ByteValue[12],
184
 
                                                (byte) guidAttr.ByteValue[13],
185
 
                                                (byte) guidAttr.ByteValue[14],
186
 
                                                (byte) guidAttr.ByteValue[15] );
187
 
 
188
 
                                        ldapGuid = cGuid.ToString();
189
 
                                }
190
 
                        }
191
 
                        catch{}
192
 
                        return ldapGuid;
193
 
                }
194
 
 
195
 
                private bool IsUser( String[] objectClasses )
196
 
                {
197
 
                        try
198
 
                        {
199
 
                                foreach( string s in objectClasses )
200
 
                                {
201
 
                                        string lower = s.ToLower();
202
 
                                        if ( lower == "inetorgperson" )
203
 
                                        {
204
 
                                                return true;
205
 
                                        }
206
 
                                        else if ( lower == "organizationalPerson" )
207
 
                                        {
208
 
                                                return true;
209
 
                                        }
210
 
                                }
211
 
                        }
212
 
                        catch( Exception e )
213
 
                        {
214
 
                                log.Error( "IsUser failed with exception" );
215
 
                                log.Error( e.Message );
216
 
                        }
217
 
                        return false;
218
 
                }
219
 
 
220
 
                private bool IsGroup( String[] objectClasses )
221
 
                {
222
 
                        try
223
 
                        {
224
 
                                foreach( string s in objectClasses )
225
 
                                {
226
 
                                        if ( s.ToLower() == "groupofnames" )
227
 
                                        {
228
 
                                                return true;
229
 
                                        }
230
 
                                }
231
 
                        }
232
 
                        catch( Exception e )
233
 
                        {
234
 
                                log.Error( "IsGroup failed with exception" );
235
 
                                log.Error( e.Message );
236
 
                        }
237
 
                        return false;
238
 
                }
239
 
 
240
 
                private bool IsContainer( String[] objectClasses )
241
 
                {
242
 
                        bool isContainer = false;
243
 
 
244
 
                        try
245
 
                        {
246
 
                                foreach( string s in objectClasses )
247
 
                                {
248
 
                                        string lower = s.ToLower();
249
 
                                        if ( lower == "organization" )
250
 
                                        {
251
 
                                                log.Debug( "Processing Organization Object..." );
252
 
                                                isContainer = true;
253
 
                                                break;
254
 
                                        }
255
 
                                        else if ( lower == "organizationalunit" )
256
 
                                        {
257
 
                                                isContainer = true;
258
 
                                                log.Debug( "Processing OrganizationalUnit Object..." );
259
 
                                                break;
260
 
                                        }
261
 
                                        else if ( lower == "country" )
262
 
                                        {
263
 
                                                isContainer = true;
264
 
                                                log.Debug( "Processing Country Object..." );
265
 
                                                break;
266
 
                                        }
267
 
                                        else if ( lower == "locality" )
268
 
                                        {
269
 
                                                isContainer = true;
270
 
                                                log.Debug( "Processing Locality Object..." );
271
 
                                                break;
272
 
                                        }
273
 
                                        else if ( lower == "container" )
274
 
                                        {
275
 
                                                isContainer = true;
276
 
                                                log.Debug( "Processing Container Object..." );
277
 
                                                break;
278
 
                                        }
279
 
                                }
280
 
                        }
281
 
                        catch( Exception e )
282
 
                        {
283
 
                                log.Error( "IsContainer failed with exception" );
284
 
                                log.Error( e.Message );
285
 
                        }
286
 
 
287
 
                        return isContainer;
288
 
                }
289
 
 
290
 
                private void ProcessSearchUser( LdapConnection connection, String searchUser )
291
 
                {
292
 
                        // Since the first version of the iFolder 3.0 only
293
 
                        // exposes a username, firstname, lastname and full
294
 
                        // name, we'll limit the scope of the search
295
 
                        string[] searchAttributes = {   
296
 
                                                                                        "modifytimestamp",
297
 
                                                                                        ldapSettings.NamingAttribute,
298
 
                                                                                        "cn",
299
 
                                                                                        "sn", 
300
 
                                                                                        "objectGUID",
301
 
                                                                                        "givenName", 
302
 
                                                                                        "ou" };
303
 
 
304
 
                        log.Debug( "ProcessSearchUser(" + searchUser + ")" );
305
 
 
306
 
                        try
307
 
                        {
308
 
                                LdapEntry ldapEntry = connection.Read( searchUser, searchAttributes );
309
 
                                ProcessUserEntry( ldapEntry );
310
 
                        }
311
 
                        catch( SimiasShutdownException s )
312
 
                        {
313
 
                                throw s;
314
 
                        }
315
 
                        catch( LdapException e )
316
 
                        {
317
 
                                log.Error( e.LdapErrorMessage );
318
 
                                log.Error( e.StackTrace );
319
 
                        }
320
 
                        catch( Exception e ) 
321
 
                        {
322
 
                                log.Error( e.Message );
323
 
                                log.Error( e.StackTrace );
324
 
                        }
325
 
                }
326
 
 
327
 
                // If the configured Simias Admin is different than the SimiasAdmin
328
 
                // identified in the store, make all the changes necessary to
329
 
                // make the configured admin the store admin.
330
 
                private void ChangeSimiasAdmin( LdapConnection conn )
331
 
                {
332
 
                        char[] dnDelimiters = {',', '='};
333
 
                        LdapEntry entry = null;
334
 
                        Property dn;
335
 
                        string commonName;
336
 
                        string ldapGuid;
337
 
                        string[] searchAttributes = { "cn", "sn", "objectGUID" };
338
 
 
339
 
                        try
340
 
                        {
341
 
                                // Nothing in the config for a SimiasAdmin - we're done here
342
 
                                if ( ldapSettings.AdminDN == null || ldapSettings.AdminDN == "" )
343
 
                                {
344
 
                                        return;
345
 
                                }
346
 
 
347
 
                                // If the SimiasAdmin has been changed in the Simias.config, which BTW
348
 
                                // is not something that is exposed in the normal management UI, 
349
 
                                // we need to verify the new SimiasAdmin exists in the directory,
350
 
                                // check if the new admin exists in local domain memberlist (and
351
 
                                // if he doesn't create him), transfer default domain ownership
352
 
                                // to the new SimiasAdmin and lastly transfer ownership of all
353
 
                                // orphaned iFolders to the new SimiasAdmin.
354
 
 
355
 
                                try
356
 
                                {
357
 
                                        entry = conn.Read( ADSync.ldapSettings.AdminDN, searchAttributes );
358
 
                                }
359
 
                                catch( LdapException lEx )
360
 
                                {
361
 
                                        log.Error( "Could not verify the newly configured Simias Administrator in the directory" );
362
 
                                        log.Error( lEx.Message );
363
 
                                }
364
 
                                catch( Exception e1 )
365
 
                                {
366
 
                                        log.Error( "Could not verify the newly configured Simias Administrator in the directory" );
367
 
                                        log.Error( e1.Message );
368
 
                                }
369
 
 
370
 
                                if ( entry == null )
371
 
                                {
372
 
                                        return;
373
 
                                }
374
 
 
375
 
                                ldapGuid = GetLdapGuid( entry );
376
 
                                if ( ldapGuid == null || ldapGuid == "" )
377
 
                                {
378
 
                                        return;
379
 
                                }
380
 
 
381
 
                                // Get the common name from the Simias.config.AdminDN entry
382
 
                                string[] components = ADSync.ldapSettings.AdminDN.Split( dnDelimiters );
383
 
                                commonName = ( components[0].ToLower() == "cn" ) ? components[1] : components[0];
384
 
                                if ( commonName == null || commonName == "" )
385
 
                                {
386
 
                                        return;
387
 
                                }
388
 
 
389
 
                                store = Store.GetStore();
390
 
                                if ( domain == null )
391
 
                                {
392
 
                                        domain = store.GetDomain( store.DefaultDomain );
393
 
                                        if ( domain == null )
394
 
                                        {
395
 
                                                throw new SimiasException( "Enterprise domain does not exist!" );
396
 
                                        }
397
 
                                }
398
 
 
399
 
                                Member member = domain.GetMemberByName( commonName );
400
 
                                if ( member == null )
401
 
                                {
402
 
                                        // Create the member with the Ldap guid
403
 
                                        member = 
404
 
                                                new Member(     commonName,     ldapGuid, Simias.Storage.Access.Rights.ReadOnly );
405
 
                                        member.Properties.ModifyProperty( "DN", ldapSettings.AdminDN );
406
 
                                }
407
 
 
408
 
                                Property lguid = new Property( "LdapGuid", ldapGuid );
409
 
                                lguid.LocalProperty = true;
410
 
                                member.Properties.ModifyProperty( lguid );
411
 
                                domain.Commit( member );
412
 
 
413
 
                                // Transfer ownership of all collections owned by the 
414
 
                                // previous admin that have the orphaned property
415
 
                                Property orphaned;
416
 
                                ICSList subList = store.GetCollectionsByOwner( domain.Owner.ID, domain.ID ); 
417
 
                                foreach ( ShallowNode sn in subList )
418
 
                                {
419
 
                                        // Get the collection object for this node.
420
 
                                        Collection c = store.GetCollectionByID( sn.CollectionID );
421
 
                                        if ( c != null )
422
 
                                        {
423
 
                                                orphaned = c.Properties.GetSingleProperty( "OrphanedOwner" );
424
 
                                                if ( orphaned != null )
425
 
                                                {
426
 
                                                        dn = c.Owner.Properties.GetSingleProperty( "DN" );
427
 
                                                        if ( dn != null )
428
 
                                                        {
429
 
                                                                c.PreviousOwner = dn.Value.ToString();
430
 
                                                                c.Commit();
431
 
                                                        }
432
 
 
433
 
                                                        c.Commit( c.ChangeOwner( member, Simias.Storage.Access.Rights.ReadWrite ) );
434
 
                                                }
435
 
                                        }
436
 
                                }
437
 
 
438
 
                                // For now I'm just going to leave the LdapGuid property
439
 
                                // on the old SimiasAdmin
440
 
                                dn = domain.Owner.Properties.GetSingleProperty( "DN" );
441
 
                                if ( dn != null )
442
 
                                {
443
 
                                        domain.PreviousOwner = dn.Value.ToString();
444
 
                                        domain.Commit();
445
 
                                }
446
 
                                
447
 
                                domain.Commit( domain.ChangeOwner( member, Simias.Storage.Access.Rights.ReadWrite ) );
448
 
                        }
449
 
                        catch( Exception vsa )
450
 
                        {
451
 
                                log.Error( vsa.Message );
452
 
                                log.Error( vsa.StackTrace );
453
 
                        }
454
 
                }
455
 
 
456
 
                // The SimiasAdmin is processed differently than normal simias users because
457
 
                // the account is aleady created in the Simias store before LdapSync runs
458
 
                // so the GUID has already been created.  The SimiasAdmin must always exist in the
459
 
                // store and the DN entry in the store must be correct with the Distinguished
460
 
                // Name in the directory.  LdapSync counts on the AdminDN entry in Simias.config
461
 
                // to be updated if the admin is moved in the directory.
462
 
                private void ProcessSimiasAdmin( LdapConnection conn )
463
 
                {
464
 
                        // Since the first version of the iFolder 3.0 only
465
 
                        // exposes a username, firstname, lastname and full
466
 
                        // name, we'll limit the scope of the search
467
 
                        string[] searchAttributes = {   
468
 
                                                                                        "modifytimestamp",
469
 
                                                                                        ldapSettings.NamingAttribute,
470
 
                                                                                        "cn", 
471
 
                                                                                        "sn", 
472
 
                                                                                        "objectGUID",
473
 
                                                                                        "givenName" }; 
474
 
 
475
 
                        char[] dnDelimiters = {',', '='};
476
 
                        LdapEntry entry = null;
477
 
                        LdapAttribute timeStampAttr = null;
478
 
                        Member cMember = null;
479
 
                        Property dn = null;
480
 
                        string ldapGuid = null;
481
 
 
482
 
                        log.Debug( "ProcessSimiasAdmin( " + ldapSettings.AdminDN + ")" );
483
 
 
484
 
                        string namingContext = "";
485
 
                        entry = conn.Read( "", new string[] { "defaultNamingContext" } );
486
 
                        if ( entry != null )
487
 
                        {
488
 
                                namingContext = entry.getAttribute( "defaultNamingContext" ).StringValue;
489
 
                        }
490
 
 
491
 
                        if ( domain == null )
492
 
                        {
493
 
                                store = Store.GetStore();
494
 
                                domain = store.GetDomain( store.DefaultDomain );
495
 
                                if ( domain == null )
496
 
                                {
497
 
                                        throw new SimiasException( "Enterprise domain does not exist!" );
498
 
                                }
499
 
                        }
500
 
 
501
 
                        // If the DN property has never been set on the SimiasAdmin,
502
 
                        // set it now
503
 
                        cMember = domain.Owner;
504
 
                        dn = cMember.Properties.GetSingleProperty( "DN" );
505
 
                        if ( dn == null || dn.Value.ToString() == "" )
506
 
                        {
507
 
                                if ( ldapSettings.AdminDN != null && ldapSettings.AdminDN != "" )
508
 
                                {
509
 
                                        dn = new Property( "DN", ldapSettings.AdminDN );
510
 
                                        cMember.Properties.ModifyProperty( dn );
511
 
                                }
512
 
                        }
513
 
 
514
 
                        // Check if the Simias Admin has changed in configuration
515
 
                        if ( ldapSettings.AdminDN != null && ldapSettings.AdminDN != "" &&
516
 
                                dn.Value.ToString() != ldapSettings.AdminDN )
517
 
                        {
518
 
                                ChangeSimiasAdmin( conn );
519
 
                                cMember = domain.Owner;
520
 
                        }
521
 
 
522
 
                        // The Simias admin is tracked in the directory by the directory
523
 
                        // guid.  Make sure the guid is stored in the node
524
 
                        Property lguidProp = cMember.Properties.GetSingleProperty( "LdapGuid" );
525
 
                        if ( lguidProp == null )
526
 
                        {
527
 
                                // This must be the first time thru so let's get the directory
528
 
                                // entry based on the configured DN
529
 
                                try
530
 
                                {
531
 
                                        entry = conn.Read( ldapSettings.AdminDN, searchAttributes );
532
 
                                }
533
 
                                catch( LdapException lEx )
534
 
                                {
535
 
                                        log.Error( "The Simias Administrator does not exist in the Ldap directory as configured in Simias.config!" );
536
 
                                        log.Error( lEx.Message );
537
 
                                }
538
 
                                catch( Exception e1 )
539
 
                                {
540
 
                                        log.Error( "The Simias Administrator does not exist in the Ldap directory as configured in Simias.config!" );
541
 
                                        log.Error( e1.Message );
542
 
                                }
543
 
 
544
 
                                if ( entry != null )
545
 
                                {
546
 
                                        ldapGuid = GetLdapGuid( entry );
547
 
                                        lguidProp = new Property( "LdapGuid", ldapGuid );
548
 
                                        lguidProp.LocalProperty = true;
549
 
                                        cMember.Properties.ModifyProperty( lguidProp );
550
 
                                }
551
 
                        }
552
 
                        else
553
 
                        {
554
 
                                ldapGuid = lguidProp.Value.ToString();
555
 
                        }
556
 
 
557
 
                        if ( ldapGuid != null )
558
 
                        {
559
 
                                try
560
 
                                {
561
 
                                        entry = null;
562
 
 
563
 
                                        // Now go find the SimiasAdmin in the Ldap directory
564
 
                                        string guidFilter = BuildGuidFilter( ldapGuid );
565
 
                                        LdapSearchResults results = 
566
 
                                                conn.Search(
567
 
                                                namingContext,
568
 
                                                LdapConnection.SCOPE_SUB, 
569
 
                                                "(&(objectclass=organizationalPerson)" + guidFilter + ")",
570
 
                                                searchAttributes,
571
 
                                                false);
572
 
                                        if ( results.hasMore() == true )
573
 
                                        {
574
 
                                                entry = results.next();
575
 
                                        }
576
 
                                }
577
 
                                catch ( LdapException e )
578
 
                                {
579
 
                                        log.Error( e.LdapErrorMessage );
580
 
                                        log.Error( e.StackTrace );
581
 
                                }
582
 
                                catch ( Exception e )
583
 
                                {
584
 
                                        log.Error( e.Message );
585
 
                                        log.Error( e.StackTrace );
586
 
                                }
587
 
 
588
 
                                if ( entry != null )
589
 
                                {
590
 
                                        //
591
 
                                        // check if the ldap object's time stamp has changed
592
 
                                        //
593
 
                                        try
594
 
                                        {
595
 
                                                timeStampAttr = entry.getAttribute( "modifytimestamp" );
596
 
                                                Property pStamp = 
597
 
                                                        cMember.Properties.GetSingleProperty( "LdapTimeStamp" );
598
 
 
599
 
                                                if ( ( pStamp == null ) ||
600
 
                                                        ( pStamp != null && 
601
 
                                                        (string) pStamp.Value != timeStampAttr.StringValue ) )
602
 
                                                {
603
 
                                                        // The time stamp changed let's look at first and
604
 
                                                        // last name
605
 
        
606
 
                                                        try
607
 
                                                        {
608
 
                                                                bool changed = false;
609
 
        
610
 
                                                                // If we're tracking by ldap see if the naming attribute
611
 
                                                                // has changed
612
 
                                                                LdapAttribute namingAttr = entry.getAttribute( ldapSettings.NamingAttribute );
613
 
                                                                if ( namingAttr != null && namingAttr.StringValue.Length != 0 )
614
 
                                                                {
615
 
                                                                        if ( namingAttr.StringValue != cMember.Name )
616
 
                                                                        {
617
 
                                                                                cMember.Name = namingAttr.StringValue;
618
 
                                                                        }
619
 
                                                                }
620
 
        
621
 
                                                                LdapAttribute givenAttr = entry.getAttribute( "givenName" );
622
 
                                                                if ( givenAttr != null && givenAttr.StringValue.Length != 0 )
623
 
                                                                {
624
 
                                                                        if ( givenAttr.StringValue != cMember.Given )
625
 
                                                                        {
626
 
                                                                                changed = true;
627
 
                                                                                cMember.Given = givenAttr.StringValue;
628
 
                                                                        }
629
 
                                                                }
630
 
 
631
 
                                                                LdapAttribute sirAttr = entry.getAttribute( "sn" );
632
 
                                                                if ( sirAttr != null && sirAttr.StringValue.Length != 0 )
633
 
                                                                {
634
 
                                                                        if ( sirAttr.StringValue != cMember.Family )
635
 
                                                                        {
636
 
                                                                                cMember.Family = sirAttr.StringValue;
637
 
                                                                                changed = true;
638
 
                                                                        }
639
 
                                                                }
640
 
 
641
 
 
642
 
                                                                // If the entry has changed and we have a valid
643
 
                                                                // family and given
644
 
                                                                if ( changed == true && 
645
 
                                                                        cMember.Given != null &&
646
 
                                                                        cMember.Given != "" && 
647
 
                                                                        cMember.Family != null &&
648
 
                                                                        cMember.Family != "" )
649
 
                                                                {
650
 
                                                                        cMember.FN = cMember.Given + " " + cMember.Family;
651
 
                                                                }
652
 
 
653
 
                                                                // Did the distinguished name change?
654
 
                                                                Property dnProp = cMember.Properties.GetSingleProperty( "DN" );
655
 
                                                                if ( dnProp != null && ( dnProp.ToString() != entry.DN ) )
656
 
                                                                {
657
 
                                                                        dnProp.Value = entry.DN;
658
 
                                                                        cMember.Properties.ModifyProperty( "DN", dnProp );
659
 
                                                                }
660
 
                                                        }
661
 
                                                        catch {}
662
 
 
663
 
                                                        pStamp = new Property( "LdapTimeStamp", timeStampAttr.StringValue );
664
 
                                                        pStamp.LocalProperty = true;
665
 
                                                        cMember.Properties.ModifyProperty( pStamp );
666
 
                                                }
667
 
                                        }
668
 
                                        catch{}
669
 
                                }
670
 
                                else
671
 
                                {
672
 
                                        log.Error( "The Simias administrator could not be verified in the directory!" );
673
 
                                        log.Error( "Please update Simias.config with a valid Ldap user" );
674
 
                                }
675
 
                        }
676
 
                        else
677
 
                        {
678
 
                                log.Error( "The Simias administrator could not be verified in the directory!" );
679
 
                                log.Error( "Please update Simias.config with a valid Ldap user" );
680
 
                        }
681
 
 
682
 
                        // Now matter what always update the sync guid so
683
 
                        // the SimiasAdmin won't be deleted from Simias
684
 
 
685
 
                        cMember.Properties.ModifyProperty( state.SyncGuid );
686
 
                        domain.Commit( cMember );
687
 
                }
688
 
 
689
 
                private void ProcessSearchGroup( LdapConnection conn, String searchGroup )
690
 
                {
691
 
                        string[] searchAttributes = {
692
 
                                                                                        "objectClass",
693
 
                                                                                        "cn",
694
 
                                                                                        "member" };
695
 
 
696
 
                        log.Debug( "ProcessSearchGroup(" + searchGroup + ")" );
697
 
 
698
 
                        int count = 0;
699
 
 
700
 
                        try
701
 
                        {
702
 
                                LdapEntry ldapEntry = conn.Read( searchGroup, searchAttributes );
703
 
                                String[] members = ldapEntry.getAttribute("member").StringValueArray;
704
 
        
705
 
                                foreach( String member in members )
706
 
                                {
707
 
                                        // Check if the sync engine wants us to abort
708
 
                                        if ( this.abort == true )
709
 
                                        {
710
 
                                                return;
711
 
                                        }
712
 
 
713
 
                                        log.Debug( "   Processing member: " + member );
714
 
                                        count++;
715
 
                                        ProcessSearchUser( conn, member );
716
 
                                }
717
 
                        }
718
 
                        catch( SimiasShutdownException s )
719
 
                        {
720
 
                                throw s;
721
 
                        }
722
 
                        catch( LdapException e )
723
 
                        {
724
 
                                log.Error( e.LdapErrorMessage );
725
 
                                log.Error( e.StackTrace );
726
 
                        }
727
 
                        catch( Exception e )
728
 
                        {
729
 
                                log.Error( e.Message );
730
 
                                log.Error( e.StackTrace );
731
 
                        }
732
 
 
733
 
                        log.Debug( "Processed " + count.ToString() + " entries" );
734
 
                }
735
 
 
736
 
                private void ProcessSearchContainer(LdapConnection conn, String searchContainer)
737
 
                {
738
 
                        String searchFilter = "(objectclass=user)";
739
 
                        string[] searchAttributes = {   
740
 
                                                                                        "modifytimestamp",
741
 
                                                                                        ldapSettings.NamingAttribute,
742
 
                                                                                        "cn", 
743
 
                                                                                        "sn", 
744
 
                                                                                        "objectGUID",
745
 
                                                                                        "givenName", 
746
 
                                                                                        "ou" };
747
 
 
748
 
                        log.Debug( "ProcessSearchContainer(" + searchContainer + ")" );
749
 
 
750
 
                        int count = 0;
751
 
                        LdapSearchConstraints searchConstraints = new LdapSearchConstraints();
752
 
                        searchConstraints.MaxResults = 0;
753
 
 
754
 
                        LdapSearchQueue queue = 
755
 
                                conn.Search(
756
 
                                searchContainer, 
757
 
                                LdapConnection.SCOPE_SUB, 
758
 
                                searchFilter, 
759
 
                                searchAttributes, 
760
 
                                false,
761
 
                                (LdapSearchQueue) null,
762
 
                                searchConstraints);
763
 
 
764
 
                        LdapMessage ldapMessage;
765
 
                        while( ( ldapMessage = queue.getResponse() ) != null )
766
 
                        {
767
 
                                // Check if the sync engine wants us to abort
768
 
                                if ( this.abort == true )
769
 
                                {
770
 
                                        return;
771
 
                                }
772
 
 
773
 
                                if ( ldapMessage is LdapSearchResult )
774
 
                                {
775
 
                                        LdapEntry cEntry = ((LdapSearchResult) ldapMessage).Entry;
776
 
                                        if (cEntry == null)
777
 
                                        {
778
 
                                                continue;
779
 
                                        }
780
 
 
781
 
                                        try
782
 
                                        {
783
 
                                                ProcessUserEntry( cEntry );
784
 
                                                count++;
785
 
                                        }
786
 
                                        catch( SimiasShutdownException s )
787
 
                                        {
788
 
                                                log.Error( s.Message );
789
 
                                                throw s;
790
 
                                        }
791
 
                                        catch( LdapException e )
792
 
                                        {
793
 
                                                log.Error( "   Failed processing: " + cEntry.DN );
794
 
                                                log.Error( e.LdapErrorMessage );
795
 
                                                log.Error( e.StackTrace );
796
 
                                        }
797
 
                                        catch( Exception e )
798
 
                                        {
799
 
                                                log.Error( "   Failed processing: " + cEntry.DN );
800
 
                                                log.Error( e.Message );
801
 
                                                log.Error( e.StackTrace );
802
 
                                        }
803
 
                                }
804
 
                        }
805
 
 
806
 
                        log.Debug( "Processed " + count.ToString() + " entries" );
807
 
                }
808
 
 
809
 
                private void ProcessUserEntry( LdapEntry entry )
810
 
                {
811
 
                        log.Debug( "ProcessUserEntry(" + entry.DN + ")" );
812
 
 
813
 
                        string commonName = String.Empty;
814
 
                        string firstName = String.Empty;
815
 
                        string lastName = String.Empty;
816
 
                        string fullName = String.Empty;
817
 
                        string distinguishedName = String.Empty;
818
 
                        string ldapGuid = null;
819
 
 
820
 
                        char[] dnDelimiters = {',', '='};
821
 
                        LdapAttribute timeStampAttr = null;
822
 
 
823
 
                        bool attrError = false;
824
 
                        try
825
 
                        {
826
 
                                // get the last update time
827
 
                                timeStampAttr = entry.getAttribute( "modifytimestamp" );
828
 
 
829
 
                                ldapGuid = GetLdapGuid( entry );
830
 
                                distinguishedName = entry.DN;
831
 
 
832
 
                                // retrieve from configuration the directory attribute configured
833
 
                                // for naming in Simias.  
834
 
                                LdapAttribute cAttr = 
835
 
                                        entry.getAttribute( ldapSettings.NamingAttribute );
836
 
                                if ( cAttr != null && cAttr.StringValue.Length != 0 )
837
 
                                {
838
 
                                        commonName = cAttr.StringValue;
839
 
                                }
840
 
                                else
841
 
                                        if ( ldapSettings.NamingAttribute.ToLower() == LdapSettings.DefaultNamingAttribute.ToLower() )
842
 
                                {
843
 
                                        // If the naming attribute is default (cn) then we want to continue
844
 
                                        // to work the way we previously did so we don't break any existing installs.
845
 
                                        //
846
 
                                        // If the distinguishing attribute did not exist,
847
 
                                        // then make the Simias username the first component
848
 
                                        // of the ldap DN.
849
 
                                        string[] components = entry.DN.Split( dnDelimiters );
850
 
                                        commonName = components[1];
851
 
                                }
852
 
 
853
 
                                LdapAttribute givenAttr = entry.getAttribute( "givenName" );
854
 
                                if ( givenAttr != null && givenAttr.StringValue.Length != 0 )
855
 
                                {
856
 
                                        firstName = givenAttr.StringValue as string;
857
 
                                }
858
 
 
859
 
                                LdapAttribute sirAttr = entry.getAttribute( "sn" );
860
 
                                if ( sirAttr != null && sirAttr.StringValue.Length != 0 )
861
 
                                {
862
 
                                        lastName = sirAttr.StringValue as string;
863
 
                                }
864
 
 
865
 
                                if ( firstName != null && lastName != null )
866
 
                                {
867
 
                                        fullName = firstName + " " + lastName;
868
 
                                }
869
 
                        }
870
 
                        catch( Exception gEx )
871
 
                        {
872
 
                                log.Error( gEx.Message );
873
 
                                log.Error( gEx.StackTrace );
874
 
 
875
 
                                state.ReportError( gEx.Message );
876
 
                                attrError = true;
877
 
                        }
878
 
 
879
 
                        // No exception were generated gathering member info
880
 
                        // so call the sync engine to process this member
881
 
                        if ( attrError == false )
882
 
                        {
883
 
                                if ( timeStampAttr != null && timeStampAttr.StringValue.Length != 0 )
884
 
                                {
885
 
                                        Property ts = new Property( "LdapTimeStamp", timeStampAttr.StringValue );
886
 
                                        ts.LocalProperty = true;
887
 
                                        Property[] propertyList = { ts };
888
 
 
889
 
                                        state.ProcessMember(
890
 
                                                ldapGuid,
891
 
                                                commonName,
892
 
                                                firstName,
893
 
                                                lastName,
894
 
                                                fullName,
895
 
                                                distinguishedName,
896
 
                                                propertyList );
897
 
                                }
898
 
                                else
899
 
                                {
900
 
                                        state.ProcessMember(
901
 
                                                ldapGuid,
902
 
                                                commonName,
903
 
                                                firstName,
904
 
                                                lastName,
905
 
                                                fullName,
906
 
                                                distinguishedName,
907
 
                                                null );
908
 
                                }
909
 
                        }
910
 
                }
911
 
                
912
 
                #endregion
913
 
 
914
 
                #region Public Methods
915
 
                /// <summary>
916
 
                /// Call to abort an in process synchronization
917
 
                /// </summary>
918
 
                /// <returns>N/A</returns>
919
 
                public void Abort()
920
 
                {
921
 
                        abort = true;
922
 
                }
923
 
                
924
 
                /// <summary>
925
 
                /// Call to inform a provider to start a synchronization cycle
926
 
                /// </summary>
927
 
                /// <returns> True - provider successfully finished a sync cycle, 
928
 
                /// False - provider failed the sync cycle
929
 
                /// </returns>
930
 
                public bool Start( Simias.IdentitySync.State State )
931
 
                {
932
 
                        log.Debug( "Start called" );
933
 
 
934
 
                        bool status = false;
935
 
                        abort = false;
936
 
                        try
937
 
                        {
938
 
                                this.state = State;
939
 
 
940
 
                                try
941
 
                                {       
942
 
                                        ldapSettings = LdapSettings.Get( Store.StorePath );
943
 
                                        log.Debug( "new LdapConnection" );
944
 
                                        conn = new LdapConnection();
945
 
 
946
 
                                        log.Debug( "Connecting to: " + ldapSettings.Host + " on port: " + ldapSettings.Port.ToString() );
947
 
                                        conn.SecureSocketLayer = ldapSettings.SSL;
948
 
                                        conn.Connect( ldapSettings.Host, ldapSettings.Port );
949
 
 
950
 
                                        ProxyUser proxy = new ProxyUser();
951
 
 
952
 
                                        log.Debug( "Binding as: " + proxy.UserDN );
953
 
                                        conn.Bind( proxy.UserDN, proxy.Password );
954
 
 
955
 
                                        ProcessSimiasAdmin( conn );
956
 
                                        ProcessSearchObjects( conn, ldapSettings );
957
 
                                }
958
 
                                catch( SimiasShutdownException s )
959
 
                                {
960
 
                                        log.Error( s.Message );
961
 
                                        syncException = s;
962
 
                                        syncStatus = Simias.LdapProvider.Status.SyncThreadDown;
963
 
                                }
964
 
                                catch( LdapException e )
965
 
                                {
966
 
                                        log.Error( e.LdapErrorMessage );
967
 
                                        log.Error( e.StackTrace );
968
 
                                        syncException = e;
969
 
                                        syncStatus = 
970
 
                                                ( conn == null )
971
 
                                                ? Simias.LdapProvider.Status.LdapConnectionFailure
972
 
                                                : Simias.LdapProvider.Status.LdapAuthenticationFailure;
973
 
 
974
 
                                        state.ReportError( e.LdapErrorMessage );
975
 
                                }
976
 
                                catch(Exception e)
977
 
                                {
978
 
                                        log.Error( e.Message );
979
 
                                        log.Error( e.StackTrace );
980
 
                                        syncException = e;
981
 
                                        syncStatus = Simias.LdapProvider.Status.InternalException;
982
 
 
983
 
                                        state.ReportError( e.Message );
984
 
                                }
985
 
                                finally
986
 
                                {
987
 
                                        if ( conn != null )
988
 
                                        {
989
 
                                                log.Debug( "Disconnecting Ldap connection" );
990
 
                                                conn.Disconnect();
991
 
                                                conn = null;
992
 
                                        }
993
 
                                }       
994
 
                                status = true;
995
 
                        }
996
 
                        catch( Exception e )
997
 
                        {
998
 
                                log.Error( e.Message );
999
 
                                log.Error( e.StackTrace );
1000
 
                                State.ReportError( e.Message );
1001
 
                        }
1002
 
                        
1003
 
                        return status;
1004
 
                }
1005
 
                #endregion
1006
 
        }
1007
 
}