    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/tools/security/ActiveDirectoryImporter.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.tools.security;
    037
    038    import java.io.FileInputStream;
    039    import java.io.IOException;
    040    import java.io.PrintWriter;
    041    import java.io.StringWriter;
    042    import java.util.ArrayList;
    043    import java.util.HashMap;
    044    import java.util.Hashtable;
    045    import java.util.Iterator;
    046    import java.util.Properties;
    047
    048    import javax.naming.Context;
    049    import javax.naming.NamingEnumeration;
    050    import javax.naming.NamingException;
    051    import javax.naming.directory.Attribute;
    052    import javax.naming.directory.Attributes;
    053    import javax.naming.directory.SearchControls;
    054    import javax.naming.directory.SearchResult;
    055    import javax.naming.ldap.Control;
    056    import javax.naming.ldap.InitialLdapContext;
    057    import javax.naming.ldap.LdapContext;
    058    import javax.naming.ldap.PagedResultsControl;
    059    import javax.naming.ldap.PagedResultsResponseControl;
    060
    061    import org.deegree.framework.mail.EMailMessage;
    062    import org.deegree.framework.mail.MailHelper;
    063    import org.deegree.framework.mail.SendMailException;
    064    import org.deegree.security.GeneralSecurityException;
    065    import org.deegree.security.UnauthorizedException;
    066    import org.deegree.security.drm.ManagementException;
    067    import org.deegree.security.drm.SecurityAccess;
    068    import org.deegree.security.drm.SecurityAccessManager;
    069    import org.deegree.security.drm.SecurityHelper;
    070    import org.deegree.security.drm.SecurityTransaction;
    071    import org.deegree.security.drm.UnknownException;
    072    import org.deegree.security.drm.model.Group;
    073    import org.deegree.security.drm.model.User;
    074
    075    /**
    076     * This class provides the functionality to synchronize the <code>User</code> and
    077     * <code>Group</code> instances stored in a <code>SecurityManager</code> with an
    078     * ActiveDirectory-Server.
    079     * <p>
    080     * Synchronization involves four steps:
    081     * <ul>
    082     * <li>synchronization of groups
    083     * <li>synchronization of users
    084     * <li>updating of the special group "SEC_ALL" (contains all users)
    085     * <li>testing of subadmin-role validity (only one role per user max)
    086     * </ul>
    087     * Changes are committed after all steps succeeded. If an error occurs, changes in the
    088     * <code>SecurityManager</code> are undone.
    089     * <p>
    090     *
    091     *
    092     * @version $Revision: 18195 $
    093     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
    094     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    095     * @author last edited by: $Author: mschneider $
    096     *
    097     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    098     */
    099    public class ActiveDirectoryImporter {
    100
    101        private SecurityAccessManager manager;
    102
    103        private SecurityAccess access;
    104
    105        private SecurityTransaction trans;
    106
    107        private User admin;
    108
    109        private Hashtable<String, String> env;
    110
    111        private LdapContext ctx;
    112
    113        private Properties config;
    114
    115        // mail configuration
    116        private static String mailSender;
    117
    118        private static String mailRcpt;
    119
    120        private static String mailHost;
    121
    122        private static boolean mailLog;
    123
    124        // number of results to fetch in one batch
    125        private int pageSize = 500;
    126
    127        private StringBuffer logBuffer = new StringBuffer( 1000 );
    128
    129        /**
    130         * Constructs a new <code>ADExporter</code> -instance.
    131         * <p>
    132         *
    133         * @param config
    134         * @throws NamingException
    135         * @throws GeneralSecurityException
    136         */
    137        ActiveDirectoryImporter( Properties config ) throws NamingException, GeneralSecurityException {
    138
    139            this.config = config;
    140
    141            // retrieve mail configuration first
    142            mailSender = getPropertySafe( "mailSender" );
    143            mailRcpt = getPropertySafe( "mailRcpt" );
    144            mailHost = getPropertySafe( "mailHost" );
    145            mailLog = getPropertySafe( "mailLog" ).equals( "true" ) || getPropertySafe( "mailLog" ).equals( "yes" ) ? true
    146                                                                                                                   : false;
    147
    148            // get a SecurityManager (with an SQLRegistry)
    149            Properties registryProperties = new Properties();
    150            registryProperties.put( "driver", getPropertySafe( "sqlDriver" ) );
    151            registryProperties.put( "url", getPropertySafe( "sqlLogon" ) );
    152            registryProperties.put( "user", getPropertySafe( "sqlUser" ) );
    153            registryProperties.put( "password", getPropertySafe( "sqlPass" ) );
    154
    155            // default timeout: 20 min
    156            long timeout = 1200000;
    157            try {
    158                timeout = Long.parseLong( getPropertySafe( "timeout" ) );
    159            } catch ( NumberFormatException e ) {
    160                logBuffer.append( "Specified property value for timeout invalid. " + "Defaulting to 1200 (secs)." );
    161            }
    162
    163            if ( !SecurityAccessManager.isInitialized() ) {
    164                SecurityAccessManager.initialize( "org.deegree.security.drm.SQLRegistry", registryProperties, timeout );
    165            }
    166
    167            manager = SecurityAccessManager.getInstance();
    168            admin = manager.getUserByName( getPropertySafe( "u3rAdminName" ) );
    169            admin.authenticate( getPropertySafe( "u3rAdminPassword" ) );
    170
    171            // prepare LDAP connection
    172            String jndiURL = "ldap://" + getPropertySafe( "ldapHost" ) + ":389/";
    173            String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    174            String authenticationMode = "simple";
    175            String contextReferral = "ignore";
    176            env = new Hashtable<String, String>();
    177            env.put( Context.INITIAL_CONTEXT_FACTORY, initialContextFactory );
    178            env.put( Context.PROVIDER_URL, jndiURL );
    179            env.put( Context.SECURITY_AUTHENTICATION, authenticationMode );
    180            env.put( Context.SECURITY_PRINCIPAL, getPropertySafe( "ldapUser" ) );
    181            env.put( Context.SECURITY_CREDENTIALS, getPropertySafe( "ldapPass" ) );
    182            env.put( Context.REFERRAL, contextReferral );
    183
    184            access = manager.acquireAccess( admin );
    185            trans = manager.acquireTransaction( admin );
    186            ctx = new InitialLdapContext( env, null );
    187
    188        }
    189
    190        /**
    191         * Returns a configuration property. If it is not defined, an exception is thrown.
    192         * <p>
    193         *
    194         * @param name
    195         * @return a configuration property. If it is not defined, an exception is thrown.
    196         */
    197        private String getPropertySafe( String name ) {
    198
    199            String value = config.getProperty( name );
    200            if ( value == null ) {
    201                throw new RuntimeException( "Configuration does not define needed property '" + name + "'." );
    202            }
    203            return value;
    204        }
    205
    206        /**
    207         * Synchronizes the AD's group objects with the SecurityManager's group objects.
    208         * <p>
    209         *
    210         * @return the mapping of the String to the Groups
    211         * @throws NamingException
    212         * @throws IOException
    213         * @throws GeneralSecurityException
    214         * @throws UnauthorizedException
    215         */
    216        HashMap<String, Group> synchronizeGroups()
    217                                throws NamingException, IOException, UnauthorizedException, GeneralSecurityException {
    218            // keys are names (Strings), values are Group-objects
    219            HashMap<String, Group> groupMap = new HashMap<String, Group>( 20 );
    220            // keys are distinguishedNames (Strings), values are Group-objects
    221            HashMap<String, Group> groupMap2 = new HashMap<String, Group>( 20 );
    222            // keys are names (Strings), values are NamingEnumeration-objects
    223            HashMap<String, NamingEnumeration<?>> memberOfMap = new HashMap<String, NamingEnumeration<?>>( 20 );
    224
    225            byte[] cookie = null;
    226
    227            // specify the ids of the attributes to return
    228            String[] attrIDs = { "distinguishedName", getPropertySafe( "groupName" ), getPropertySafe( "groupTitle" ),
    229                                getPropertySafe( "groupMemberOf" ) };
    230
    231            // set SearchControls
    232            SearchControls ctls = new SearchControls();
    233            ctls.setReturningAttributes( attrIDs );
    234            ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
    235
    236            // specify the search filter to match
    237            // ask for objects that have the attribute "objectCategory" =
    238            // "CN=Group*"
    239            String filter = getPropertySafe( "groupFilter" );
    240            String context = getPropertySafe( "groupContext" );
    241
    242            // create initial PagedResultsControl
    243            ctx.setRequestControls( new Control[] { new PagedResultsControl( pageSize, false ) } );
    244
    245            // phase 1: make sure that all groups from AD are present in the
    246            // SecurityManager
    247            // (register them to the SecurityManager if necessary)
    248            do {
    249                // perform the search
    250                NamingEnumeration<?> answer = ctx.search( context, filter, ctls );
    251
    252                // process results of the last batch
    253                while ( answer.hasMoreElements() ) {
    254                    SearchResult result = (SearchResult) answer.nextElement();
    255                    Attributes atts = result.getAttributes();
    256                    String distinguishedName = (String) atts.get( "distinguishedName" ).get();
    257                    String name = (String) atts.get( getPropertySafe( "groupName" ) ).get();
    258                    String title = (String) atts.get( getPropertySafe( "groupTitle" ) ).get();
    259
    260                    // check if group is already registered
    261                    Group group = null;
    262                    try {
    263                        group = access.getGroupByName( name );
    264                    } catch ( UnknownException e ) {
    265                        // no -> register group
    266                        logBuffer.append( "Registering group: " + name + "\n" );
    267                        group = trans.registerGroup( name, title );
    268                    }
    269                    groupMap.put( name, group );
    270                    groupMap2.put( distinguishedName, group );
    271                    if ( atts.get( getPropertySafe( "groupMemberOf" ) ) != null ) {
    272                        memberOfMap.put( name, atts.get( getPropertySafe( "groupMemberOf" ) ).getAll() );
    273                    }
    274                }
    275
    276                // examine the paged results control response
    277                Control[] controls = ctx.getResponseControls();
    278                if ( controls != null ) {
    279                    for ( int i = 0; i < controls.length; i++ ) {
    280                        if ( controls[i] instanceof PagedResultsResponseControl ) {
    281                            PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
    282                            // total = prrc.getResultSize();
    283                            cookie = prrc.getCookie();
    284                        }
    285                    }
    286                }
    287
    288                if ( cookie != null ) {
    289                    // re-activate paged results
    290                    ctx.setRequestControls( new Control[] { new PagedResultsControl( pageSize, cookie, Control.CRITICAL ) } );
    291                }
    292            } while ( cookie != null );
    293
    294            // phase 2: make sure that all groups from the SecurityManager are known
    295            // to the AD
    296            // (deregister them from the SecurityManager if necessary)
    297            Group[] sMGroups = access.getAllGroups();
    298            for ( int i = 0; i < sMGroups.length; i++ ) {
    299                if ( groupMap.get( sMGroups[i].getName() ) == null && sMGroups[i].getID() != Group.ID_SEC_ADMIN
    300                     && !( sMGroups[i].getName().equals( "SEC_ALL" ) ) ) {
    301                    logBuffer.append( "Deregistering group: " + sMGroups[i].getName() + "\n" );
    302                    trans.deregisterGroup( sMGroups[i] );
    303                }
    304            }
    305
    306            // phase 3: set the membership-relations between the groups
    307            Iterator<String> it = groupMap.keySet().iterator();
    308            while ( it.hasNext() ) {
    309                String name = it.next();
    310                Group group = groupMap.get( name );
    311                NamingEnumeration<?> memberOf = memberOfMap.get( name );
    312                ArrayList<Group> memberOfList = new ArrayList<Group>( 5 );
    313
    314                if ( memberOf != null ) {
    315                    while ( memberOf.hasMoreElements() ) {
    316                        String memberGroupName = (String) memberOf.nextElement();
    317                        Group memberGroup = groupMap2.get( memberGroupName );
    318                        if ( memberGroup != null ) {
    319                            memberOfList.add( memberGroup );
    320                        } else {
    321                            logBuffer.append( "Group " + name + " is member of unknown group " + memberGroupName
    322                                              + ". Membership ignored.\n" );
    323                        }
    324                    }
    325                }
    326                Group[] newGroups = memberOfList.toArray( new Group[memberOfList.size()] );
    327                trans.setGroupsForGroup( group, newGroups );
    328            }
    329            return groupMap2;
    330        }
    331
    332        /**
    333         * Synchronizes the AD's user objects with the SecurityManager's user objects.
    334         * <p>
    335         *
    336         * @param groups
    337         *
    338         * @throws NamingException
    339         * @throws IOException
    340         * @throws GeneralSecurityException
    341         * @throws UnauthorizedException
    342         *
    343         */
    344        void synchronizeUsers( HashMap<String, Group> groups )
    345                                throws NamingException, IOException, UnauthorizedException, GeneralSecurityException {
    346            // keys are names (Strings), values are User-objects
    347            HashMap<String, User> userMap = new HashMap<String, User>( 20 );
    348            // keys are names (Strings), values are NamingEnumeration-objects
    349            HashMap<String, NamingEnumeration<?>> memberOfMap = new HashMap<String, NamingEnumeration<?>>( 20 );
    350
    351            byte[] cookie = null;
    352
    353            // specify the ids of the attributes to return
    354            String[] attrIDs = { getPropertySafe( "userName" ), getPropertySafe( "userTitle" ),
    355                                getPropertySafe( "userFirstName" ), getPropertySafe( "userLastName" ),
    356                                getPropertySafe( "userMail" ), getPropertySafe( "userMemberOf" ) };
    357
    358            SearchControls ctls = new SearchControls();
    359            ctls.setReturningAttributes( attrIDs );
    360            ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
    361
    362            // specify the search filter to match
    363            String filter = getPropertySafe( "userFilter" );
    364            String context = getPropertySafe( "userContext" );
    365
    366            // create initial PagedResultsControl
    367            ctx.setRequestControls( new Control[] { new PagedResultsControl( pageSize, false ) } );
    368
    369            // phase 1: make sure that all users from AD are present in the
    370            // SecurityManager
    371            // (register them to the SecurityManager if necessary)
    372            do {
    373                // perform the search
    374                NamingEnumeration<?> answer = ctx.search( context, filter, ctls );
    375
    376                // process results of the last batch
    377                while ( answer.hasMoreElements() ) {
    378                    SearchResult result = (SearchResult) answer.nextElement();
    379
    380                    Attributes atts = result.getAttributes();
    381                    Attribute nameAtt = atts.get( getPropertySafe( "userName" ) );
    382                    // Attribute titleAtt = atts.get( getPropertySafe( "userTitle" ) );
    383                    Attribute firstNameAtt = atts.get( getPropertySafe( "userFirstName" ) );
    384                    Attribute lastNameAtt = atts.get( getPropertySafe( "userLastName" ) );
    385                    Attribute mailAtt = atts.get( getPropertySafe( "userMail" ) );
    386                    Attribute memberOfAtt = atts.get( getPropertySafe( "userMemberOf" ) );
    387
    388                    String name = (String) nameAtt.get();
    389                    // String title = titleAtt != null ? (String) titleAtt.get() : "";
    390                    String firstName = firstNameAtt != null ? (String) firstNameAtt.get() : "" + "";
    391                    String lastName = lastNameAtt != null ? (String) lastNameAtt.get() : "" + "";
    392                    String mail = mailAtt != null ? (String) mailAtt.get() : "";
    393
    394                    // check if user is already registered
    395                    User user = null;
    396                    try {
    397                        user = access.getUserByName( name );
    398                    } catch ( UnknownException e ) {
    399                        // no -> register user
    400                        logBuffer.append( "Registering user: " + name + "\n" );
    401                        user = trans.registerUser( name, null, lastName, firstName, mail );
    402                    }
    403                    userMap.put( name, user );
    404
    405                    if ( memberOfAtt != null ) {
    406                        memberOfMap.put( name, memberOfAtt.getAll() );
    407                    }
    408                }
    409
    410                // examine the paged results control response
    411                Control[] controls = ctx.getResponseControls();
    412                if ( controls != null ) {
    413                    for ( int i = 0; i < controls.length; i++ ) {
    414                        if ( controls[i] instanceof PagedResultsResponseControl ) {
    415                            PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
    416                            // total = prrc.getResultSize();
    417                            cookie = prrc.getCookie();
    418                        }
    419                    }
    420                }
    421
    422                if ( cookie != null ) {
    423                    // re-activate paged results
    424                    ctx.setRequestControls( new Control[] { new PagedResultsControl( pageSize, cookie, Control.CRITICAL ) } );
    425                }
    426            } while ( cookie != null );
    427
    428            // phase 2: make sure that all users from the SecurityManager are known
    429            // to the AD
    430            // (deregister them from the SecurityManager if necessary)
    431            User[] sMUsers = access.getAllUsers();
    432            for ( int i = 0; i < sMUsers.length; i++ ) {
    433                if ( userMap.get( sMUsers[i].getName() ) == null && sMUsers[i].getID() != User.ID_SEC_ADMIN ) {
    434                    logBuffer.append( "Deregistering user: " + sMUsers[i].getName() + "\n" );
    435                    trans.deregisterUser( sMUsers[i] );
    436                }
    437            }
    438
    439            // phase 3: set the membership-relations between the groups and the
    440            // users
    441            Iterator<String> it = userMap.keySet().iterator();
    442            while ( it.hasNext() ) {
    443                String name = it.next();
    444                User user = userMap.get( name );
    445                NamingEnumeration<?> memberOf = memberOfMap.get( name );
    446                ArrayList<Group> memberOfList = new ArrayList<Group>( 5 );
    447                if ( memberOf != null ) {
    448                    while ( memberOf.hasMoreElements() ) {
    449                        String memberGroupName = (String) memberOf.nextElement();
    450                        Group memberGroup = groups.get( memberGroupName );
    451                        if ( memberGroup != null ) {
    452                            memberOfList.add( memberGroup );
    453                        } else {
    454                            logBuffer.append( "User " + name + " is member of unknown group " + memberGroupName
    455                                              + ". Membership ignored.\n" );
    456                        }
    457                    }
    458                }
    459                Group[] newGroups = memberOfList.toArray( new Group[memberOfList.size()] );
    460                trans.setGroupsForUser( user, newGroups );
    461            }
    462
    463        }
    464
    465        /**
    466         * Updates the special group "SEC_ALL" (contains all users).
    467         * <p>
    468         *
    469         * @throws GeneralSecurityException
    470         *
    471         */
    472        void updateSecAll()
    473                                throws GeneralSecurityException {
    474            Group secAll = null;
    475
    476            // phase1: make sure that group "SEC_ALL" exists
    477            // (register it if necessary)
    478            try {
    479                secAll = access.getGroupByName( "SEC_ALL" );
    480            } catch ( UnknownException e ) {
    481                secAll = trans.registerGroup( "SEC_ALL", "SEC_ALL" );
    482            }
    483
    484            // phase2: set all users to be members of this group
    485            User[] allUsers = access.getAllUsers();
    486            trans.setUsersInGroup( secAll, allUsers );
    487
    488        }
    489
    490        /**
    491         * Checks subadmin-role validity (each user one role max).
    492         * <p>
    493         *
    494         * @throws ManagementException
    495         * @throws GeneralSecurityException
    496         */
    497        void checkSubadminRoleValidity()
    498                                throws ManagementException, GeneralSecurityException {
    499            SecurityHelper.checkSubadminRoleValidity( access );
    500        }
    501
    502        /**
    503         * Aborts the synchronization process and undoes all changes.
    504         */
    505        public void abortChanges() {
    506            if ( manager != null && trans != null ) {
    507                try {
    508                    manager.abortTransaction( trans );
    509                } catch ( GeneralSecurityException e ) {
    510                    e.printStackTrace();
    511                }
    512            }
    513            if ( ctx != null ) {
    514                try {
    515                    ctx.close();
    516                } catch ( NamingException e ) {
    517                    e.printStackTrace();
    518                }
    519            }
    520        }
    521
    522        /**
    523         * Ends the synchronization process and commits all changes.
    524         */
    525        public void commitChanges() {
    526            if ( manager != null && trans != null ) {
    527                try {
    528                    manager.commitTransaction( trans );
    529                } catch ( GeneralSecurityException e ) {
    530                    e.printStackTrace();
    531                }
    532            }
    533            if ( ctx != null ) {
    534                try {
    535                    ctx.close();
    536                } catch ( NamingException e ) {
    537                    e.printStackTrace();
    538                }
    539            }
    540        }
    541
    542        /**
    543         * Sends an eMail to inform the admin that something went wrong.
    544         * <p>
    545         * NOTE: This is static, because it must be usable even when the construction of the ADExporter
    546         * failed.
    547         * <p>
    548         *
    549         * @param e
    550         */
    551        public static void sendError( Exception e ) {
    552
    553            try {
    554                String mailMessage = "Beim Synchronisieren des ActiveDirectory mit der HUIS-"
    555                                     + "Sicherheitsdatenbank ist ein Fehler aufgetreten.\n"
    556                                     + "Die Synchronisierung wurde NICHT durchgeführt, der letzte "
    557                                     + "Stand wurde wiederhergestellt.\n";
    558                StringWriter sw = new StringWriter();
    559                PrintWriter writer = new PrintWriter( sw );
    560                e.printStackTrace( writer );
    561                mailMessage += "\n\nDie Java-Fehlermeldung lautet:\n" + sw.getBuffer();
    562
    563                mailMessage += "\n\nMit freundlichem Gruss,\nIhr ADExporter";
    564                MailHelper.createAndSendMail(
    565                                              new EMailMessage( mailSender, mailRcpt, "Fehler im ADExporter", mailMessage ),
    566                                              mailHost );
    567            } catch ( SendMailException ex ) {
    568                ex.printStackTrace();
    569            }
    570
    571        }
    572
    573        /**
    574         * Sends an eMail with a log of the transaction.
    575         * <p>
    576         */
    577        public void sendLog() {
    578
    579            try {
    580                String mailMessage = "Die Synchronisierung der HUIS-Sicherheitsdatenbank mit "
    581                                     + "dem ActiveDirectory wurde erfolgreich durchgeführt:\n\n";
    582                if ( logBuffer.length() == 0 ) {
    583                    mailMessage += "Keine Änderungen.";
    584                } else {
    585                    mailMessage += logBuffer.toString();
    586                }
    587                mailMessage += "\n\nMit freundlichem Gruss,\nIhr ADExporter";
    588                EMailMessage emm = new EMailMessage( mailSender, mailRcpt, "ActiveDirectory Sychronisierung durchgeführt",
    589                                                     mailMessage );
    590                MailHelper.createAndSendMail( emm, mailHost );
    591            } catch ( SendMailException ex ) {
    592                ex.printStackTrace();
    593            }
    594
    595        }
    596
    597        /**
    598         * @param args
    599         * @throws Exception
    600         */
    601        public static void main( String[] args )
    602                                throws Exception {
    603
    604            if ( args.length != 1 ) {
    605                System.out.println( "USAGE: ADExporter configfile" );
    606                System.exit( 0 );
    607            }
    608
    609            long begin = System.currentTimeMillis();
    610            System.out.println( "Beginning synchronisation..." );
    611
    612            ActiveDirectoryImporter exporter = null;
    613            try {
    614                Properties config = new Properties();
    615                config.load( new FileInputStream( args[0] ) );
    616                exporter = new ActiveDirectoryImporter( config );
    617
    618                HashMap<String, Group> groups = exporter.synchronizeGroups();
    619                exporter.synchronizeUsers( groups );
    620                exporter.updateSecAll();
    621                exporter.checkSubadminRoleValidity();
    622                exporter.commitChanges();
    623            } catch ( Exception e ) {
    624                if ( exporter != null ) {
    625                    exporter.abortChanges();
    626                }
    627                sendError( e );
    628                System.err.println( "Synchronisation has been aborted. Error message: " );
    629                e.printStackTrace();
    630                System.exit( 0 );
    631            }
    632
    633            if ( mailLog ) {
    634                exporter.sendLog();
    635            }
    636
    637            System.out.println( "Synchronisation took " + ( System.currentTimeMillis() - begin ) + " milliseconds." );
    638
    639            System.exit( 0 );
    640        }
    641    }