001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/standard/security/control/StoreUsersListener.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.portal.standard.security.control;
037    
038    import java.io.BufferedWriter;
039    import java.io.File;
040    import java.io.FileWriter;
041    import java.io.IOException;
042    import java.text.ParseException;
043    import java.util.Iterator;
044    import java.util.Vector;
045    
046    import org.deegree.enterprise.control.AbstractListener;
047    import org.deegree.enterprise.control.FormEvent;
048    import org.deegree.enterprise.control.RPCException;
049    import org.deegree.enterprise.control.RPCMember;
050    import org.deegree.enterprise.control.RPCMethodCall;
051    import org.deegree.enterprise.control.RPCParameter;
052    import org.deegree.enterprise.control.RPCStruct;
053    import org.deegree.enterprise.control.RPCWebEvent;
054    import org.deegree.framework.log.ILogger;
055    import org.deegree.framework.log.LoggerFactory;
056    import org.deegree.framework.util.StringTools;
057    import org.deegree.i18n.Messages;
058    import org.deegree.security.GeneralSecurityException;
059    import org.deegree.security.drm.SecurityAccessManager;
060    import org.deegree.security.drm.SecurityTransaction;
061    import org.deegree.security.drm.model.User;
062    
063    /**
064     * This <code>Listener</code> reacts on 'storeUsers' events, extracts the contained user
065     * definitions and updates the <code>SecurityManager</code> accordingly.
066     *
067     * Access constraints:
068     * <ul>
069     * <li>only users that have the 'SEC_ADMIN'-role are allowed</li>
070     * </ul>
071     *
072     * @author <a href="mschneider@lat-lon.de">Markus Schneider </a>
073     * @author last edited by: $Author: mschneider $
074     *
075     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
076     */
077    public class StoreUsersListener extends AbstractListener {
078    
079        private static final ILogger LOG = LoggerFactory.getLogger( StoreUsersListener.class );
080    
081        //ME: added for context chooser
082        String usersDirectoryPath = null;
083    
084        String defaultContextName = null;
085    
086        String defaultContextPath = null;
087    
088        private final String STARTCONTEXT = "STARTCONTEXT";
089    
090        private final String CONTEXTNAME = "CONTEXT_NAME";
091    
092        @Override
093        public void actionPerformed( FormEvent event ) {
094    
095            SecurityAccessManager manager = null;
096            SecurityTransaction transaction = null;
097    
098            User[] users = null;
099    
100            try {
101                RPCWebEvent ev = (RPCWebEvent) event;
102                RPCMethodCall rpcCall = ev.getRPCMethodCall();
103                RPCParameter[] params = rpcCall.getParameters();
104    
105                // ME: this part concerns extracting the usersdirectory member
106                Vector<RPCParameter> vector = new Vector<RPCParameter>( params.length );
107                for ( int i = 0; i < params.length; i++ ) {
108                    vector.add( params[i] );
109                }
110    
111                boolean isUsersDirectoryFound = false;
112                boolean isDefaultContextNameFound = false;
113                boolean isDefaultContextPathFound = false;
114                Iterator<RPCParameter> it = vector.iterator();
115    
116                while ( it.hasNext() ) {
117                    RPCStruct struct = (RPCStruct) it.next().getValue();
118                    RPCMember usersDirectoryRPC = struct.getMember( "usersDirectory" );
119                    RPCMember defCnNameRPC = struct.getMember( "defaultContextName" );
120                    RPCMember defCnPathRPC = struct.getMember( "defaultContextPath" );
121    
122                    if ( usersDirectoryRPC != null ) {
123                        if ( usersDirectoryRPC.getValue() instanceof String ) {
124                            isUsersDirectoryFound = true;
125                            usersDirectoryPath = (String) usersDirectoryRPC.getValue();
126                        }
127                    }
128    
129                    if ( defCnNameRPC != null ) {
130                        if ( defCnNameRPC.getValue() instanceof String ) {
131                            isDefaultContextNameFound = true;
132                            defaultContextName = (String) defCnNameRPC.getValue();
133                        }
134                    }
135    
136                    if ( defCnPathRPC != null ) {
137                        if ( defCnPathRPC.getValue() instanceof String ) {
138                            isDefaultContextPathFound = true;
139                            defaultContextPath = (String) defCnPathRPC.getValue();
140                        }
141                    }
142                    if ( isUsersDirectoryFound || isDefaultContextNameFound || isDefaultContextPathFound ) {
143                        it.remove();
144                        break;
145                    }
146                }
147    
148                params = new RPCParameter[vector.size()];
149                for ( int i = 0; i < vector.size(); i++ ) {
150                    params[i] = vector.elementAt( i );
151                }
152                // ME: end
153    
154                // now extracting the members of each parameter
155                users = new User[params.length];
156    
157                for ( int i = 0; i < params.length; i++ ) {
158                    if ( !( params[0].getValue() instanceof RPCStruct ) ) {
159                        throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_MISSING_STRUCT" ) );
160                    }
161                    RPCStruct struct = (RPCStruct) params[i].getValue();
162    
163                    // extract user details
164                    RPCMember userIdRPC = struct.getMember( "userId" );
165                    RPCMember userNameRPC = struct.getMember( "userName" );
166                    RPCMember emailRPC = struct.getMember( "email" );
167                    RPCMember passwordRPC = struct.getMember( "password" );
168                    RPCMember firstNameRPC = struct.getMember( "firstName" );
169                    RPCMember lastNameRPC = struct.getMember( "lastName" );
170                    //ME: added for context chooser
171                    RPCMember contextNameRPC = struct.getMember( "contextName" );
172                    RPCMember contextPathRPC = struct.getMember( "contextPath" );
173    
174                    int userId;
175                    String userName = null;
176                    String email = null;
177                    String password = null;
178                    String firstName = null;
179                    String lastName = null;
180                    //ME: added for context chooser
181                    String contextName = null;
182                    String contextPath = null;
183    
184                    if ( userIdRPC == null ) {
185                        throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_MISSING_MEMBER", "user", "userId" ) );
186                    }
187                    if ( !( userIdRPC.getValue() instanceof String ) ) {
188                        throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "userId", "string" ) );
189                    }
190                    try {
191                        userId = Integer.parseInt( ( (String) userIdRPC.getValue() ) );
192                    } catch ( NumberFormatException e ) {
193                        throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "userId", "integer" ) );
194                    }
195                    // extract userName
196                    if ( userNameRPC != null ) {
197                        if ( !( userNameRPC.getValue() instanceof String ) ) {
198                            throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "userName", "string" ) );
199                        }
200                        userName = (String) userNameRPC.getValue();
201    
202                    }
203                    // extract email
204                    if ( emailRPC != null ) {
205                        if ( !( emailRPC.getValue() instanceof String ) ) {
206                            throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "email", "string" ) );
207                        }
208                        email = (String) emailRPC.getValue();
209    
210                    }
211                    // extract password
212                    if ( passwordRPC != null ) {
213                        if ( !( passwordRPC.getValue() instanceof String ) ) {
214                            throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "password", "string" ) );
215                        }
216                        password = (String) passwordRPC.getValue();
217    
218                    }
219                    // extract firstName
220                    if ( firstNameRPC != null ) {
221                        if ( !( firstNameRPC.getValue() instanceof String ) ) {
222                            throw new RPCException(
223                                                    Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "firstName", "string" ) );
224                        }
225                        firstName = (String) firstNameRPC.getValue();
226    
227                    }
228                    // extract lastName
229                    if ( lastNameRPC != null ) {
230                        if ( !( lastNameRPC.getValue() instanceof String ) ) {
231                            throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_MEMBER", "lastName", "string" ) );
232                        }
233                        lastName = (String) lastNameRPC.getValue();
234    
235                    }
236    
237                    if ( userName == null ) {
238                        throw new GeneralSecurityException( Messages.getMessage( "IGEO_STD_SEC_MISSING_MEMBER", "user",
239                                                                                 "name" ) );
240                    }
241                    if ( email == null ) {
242                        throw new GeneralSecurityException( Messages.getMessage( "IGEO_STD_SEC_MISSING_MEMBER", "user",
243                                                                                 "email address" ) );
244                    }
245    
246                    /*
247                     * getting the value only in case this is not the default context or the param is
248                     * missing
249                     *
250                     * if contextPathRPC==null, that means that no param is given, that means probably
251                     * that the init parameter method in InitUserEditor didn't get anything from the
252                     * conf_startcontext.xml
253                     *
254                     * otherwise if the contextPath is null we delete the users contexts, if it has a
255                     * value we assign it this value
256                     */
257    
258                    LOG.logDebug( "userNameRPC: " + userName );
259                    LOG.logDebug( isUsersDirectoryFound ? "true" : "false" );
260                    LOG.logDebug( contextNameRPC != null ? "context name not null" : "context name null" );
261                    LOG.logDebug( contextPathRPC != null ? "contextPath not null" : "contextpath null" );
262    
263                    if ( isUsersDirectoryFound && contextNameRPC != null ) {
264                        contextName = (String) contextNameRPC.getValue();
265                        if ( contextPathRPC != null ) {
266                            contextPath = (String) contextPathRPC.getValue();
267                        } else {
268                            contextPath = null;
269                        }
270                        updateUserDirectory( userName, contextPath, contextName );
271                    }
272                    // ME: end
273    
274                    users[i] = new User( userId, userName, password, firstName, lastName, email, null );
275                }
276    
277                for ( int i = 0; i < users.length; i++ ) {
278                    LOG.logDebug( "id: " + users[i].getID() );
279                    LOG.logDebug( "firstName: " + users[i].getFirstName() );
280                    LOG.logDebug( "lastName: " + users[i].getLastName() );
281                    LOG.logDebug( "email: " + users[i].getEmailAddress() );
282                    LOG.logDebug( "password: " + users[i].getPassword() );
283                }
284    
285                // get Transaction and perform access check
286                manager = SecurityAccessManager.getInstance();
287                transaction = SecurityHelper.acquireTransaction( this );
288                SecurityHelper.checkForAdminRole( transaction );
289    
290                // remove deleted users
291                User[] oldUsers = transaction.getAllUsers();
292                for ( int i = 0; i < oldUsers.length; i++ ) {
293                    boolean deleted = true;
294                    for ( int j = 0; j < users.length; j++ ) {
295                        if ( users[j].equals( oldUsers[i] ) ) {
296                            deleted = false;
297                        }
298                    }
299                    if ( oldUsers[i].getID() != User.ID_SEC_ADMIN && deleted ) {
300                        transaction.deregisterUser( oldUsers[i] );
301                    }
302                }
303    
304                // register all new users / update old users
305                for ( int i = 0; i < users.length; i++ ) {
306                    if ( users[i].getID() == -1 ) {
307                        transaction.registerUser( users[i].getName(), users[i].getPassword(), users[i].getLastName(),
308                                                  users[i].getFirstName(), users[i].getEmailAddress() );
309                    } else if ( users[i].getID() != User.ID_SEC_ADMIN ) {
310                        transaction.updateUser( users[i] );
311                    }
312                }
313                manager.commitTransaction( transaction );
314                transaction = null;
315    
316                getRequest().setAttribute( "MESSAGE", Messages.getMessage( "IGEO_STD_SEC_SUCCESS_INITUSEREDITOR" ) );
317            } catch ( RPCException e ) {
318                getRequest().setAttribute( "SOURCE", this.getClass().getName() );
319                getRequest().setAttribute( "MESSAGE", Messages.getMessage( "IGEO_STD_SEC_ERROR_CHANGE_REQ", e.getMessage() ) );
320                setNextPage( "error.jsp" );
321                LOG.logError( e.getMessage() );
322            } catch ( GeneralSecurityException e ) {
323                getRequest().setAttribute( "SOURCE", this.getClass().getName() );
324                getRequest().setAttribute( "MESSAGE", Messages.getMessage( "IGEO_STD_SEC_ERROR_CHANGE", e.getMessage() ) );
325                setNextPage( "error.jsp" );
326                LOG.logError( e.getMessage(), e );
327            } catch ( Exception e ) {
328                LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_UNKNOWN", StringTools.stackTraceToString( e ) ) );
329            } finally {
330                if ( manager != null && transaction != null ) {
331                    try {
332                        manager.abortTransaction( transaction );
333                    } catch ( GeneralSecurityException ex ) {
334                        LOG.logError( ex.getMessage(), ex );
335                    }
336                }
337            }
338        }
339    
340        /**
341         * ME: added for context chooser
342         *
343         * update the users directory, context.properties data, accroding to the value of contextPath
344         * also creates a user folder in case it doesn't exist
345         *
346         * @param user
347         * @param contextPath
348         * @throws IOException
349         * @throws ParseException
350         *
351         */
352        private void updateUserDirectory( String user, String contextPath, String contextName )
353                                throws IOException, ParseException {
354    
355            LOG.logDebug( "user name: " + user );
356            File usersRootDirectory = new File( usersDirectoryPath );
357    
358            File userDirectory = null;
359            try {
360                userDirectory = new File( usersRootDirectory.getCanonicalPath() + "/" + user + "/" );
361            } catch ( IOException e ) {
362                LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_CANONICAL_PATH",
363                                                   usersRootDirectory.getAbsolutePath() ) );
364                throw new IOException( Messages.getMessage( "IGEO_STD_SEC_ERROR_CANONICAL_PATH",
365                                                            usersRootDirectory.getAbsolutePath() ) );
366            }
367    
368            LOG.logDebug( "context Path " + contextPath );
369            if ( contextPath == null || contextPath.equals( "null" ) || contextPath.equals( "undefined" ) ) {
370                LOG.logDebug( "trying to create a folder" );
371                File userContextProperties = new File( userDirectory + "/" + "context.properties" );
372                if ( userContextProperties.exists() ) {
373                    try {
374                        if ( userContextProperties.delete() ) {
375                            LOG.logDebug( "context deleted successfully" );
376                        }
377    
378                        return;
379                    } catch ( SecurityException e ) {
380                        LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_ACCESSING_FILE", userContextProperties ) );
381                        throw new SecurityException( Messages.getMessage( "IGEO_STD_SEC_ERROR_ACCESSING_FILE",
382                                                                          userContextProperties ) );
383                    }
384                } else {
385                    if ( !userDirectory.exists() ) {
386                        userDirectory.mkdir();
387                    }
388                }
389                return;
390            }
391    
392            if ( !userDirectory.exists() ) {
393                userDirectory.mkdir();
394            }
395            // Here we know that the StartContext is not the default one
396            File newContext = null;
397            try {
398                newContext = new File( userDirectory.getCanonicalPath() + "/" + "context.properties" );
399            } catch ( IOException e ) {
400                LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_CANONICAL_PATH", userDirectory.getPath() ) );
401            }
402            if ( !userDirectory.exists() ) {
403                userDirectory.mkdir();
404            }
405    
406            // Here we will map the file path, in case the context doesn't exist
407            // From the Drm-Admin directorty to the portal directory
408            String outputPath = null;
409    
410            // String relativeUserDir= usersDirectoryPath + "/" + user;
411            // LOG.logDebug("sourcePath: " + relativeUserDir);
412            File absCntxtPath = new File( contextPath );
413            String[] delimiters = { "\\", "/" };
414            outputPath = RelativePath.mapRelativePath( userDirectory.getCanonicalPath(), absCntxtPath.getCanonicalPath(),
415                                                       delimiters );
416    
417            try {
418                BufferedWriter bufferedWriter = new BufferedWriter( new FileWriter( newContext.getCanonicalPath() ) );
419                bufferedWriter.flush();
420                StringBuffer buffer = new StringBuffer();
421                buffer.append( STARTCONTEXT + '=' + outputPath + System.getProperty( "line.separator" ) );
422                buffer.append( CONTEXTNAME + '=' + contextName + System.getProperty( "line.separator" ) );
423                bufferedWriter.write( buffer.toString() );
424                bufferedWriter.close();
425    
426            } catch ( IOException e ) {
427                LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_ACCESSING_FILE", newContext.getPath() ) );
428                throw new IOException( Messages.getMessage( "IGEO_STD_SEC_ERROR_ACCESSING_FILE", newContext.getPath() ) );
429            } catch ( Exception e ) {
430                LOG.logError( Messages.getMessage( "IGEO_STD_SEC_ERROR_UNKNOWN", StringTools.stackTraceToString( e ) ) );
431            }
432        }
433    }