View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.mylutece.modules.wssodatabase.authentication.util;
35  
36  import fr.paris.lutece.plugins.mylutece.modules.wssodatabase.authentication.business.WssoUser;
37  import fr.paris.lutece.portal.service.util.AppLogService;
38  import fr.paris.lutece.portal.service.util.AppPropertiesService;
39  
40  import java.text.MessageFormat;
41  
42  import java.util.ArrayList;
43  import java.util.Collection;
44  import java.util.Collections;
45  import java.util.Comparator;
46  
47  import javax.naming.CommunicationException;
48  import javax.naming.NamingEnumeration;
49  import javax.naming.NamingException;
50  import javax.naming.directory.Attributes;
51  import javax.naming.directory.DirContext;
52  import javax.naming.directory.SearchControls;
53  import javax.naming.directory.SearchResult;
54  
55  
56  /**
57   * Data authentication module for admin authentication
58   */
59  public class LdapBrowser
60  {
61      // ldap
62      private static final String PROPERTY_INITIAL_CONTEXT_PROVIDER = "mylutece-wssodatabase.ldap.initialContextProvider";
63      private static final String PROPERTY_PROVIDER_URL = "mylutece-wssodatabase.ldap.connectionUrl";
64      private static final String PROPERTY_BIND_DN = "mylutece-wssodatabase.ldap.connectionName";
65      private static final String PROPERTY_BIND_PASSWORD = "mylutece-wssodatabase.ldap.connectionPassword";
66      private static final String PROPERTY_USER_DN_SEARCH_BASE = "mylutece-wssodatabase.ldap.userBase";
67      private static final String PROPERTY_USER_DN_SEARCH_FILTER_BY_GUID = "mylutece-wssodatabase.ldap.userSearch.guid";
68      private static final String PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_SN = "mylutece-wssodatabase.ldap.userSearch.criteria.sn";
69      private static final String PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_GIVENNAME = "mylutece-wssodatabase.ldap.userSearch.criteria.givenname";
70      private static final String PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_MAIL = "mylutece-wssodatabase.ldap.userSearch.criteria.mail";
71      private static final String PROPERTY_USER_SUBTREE = "mylutece-wssodatabase.ldap.userSubtree";
72      private static final String PROPERTY_DN_ATTRIBUTE_GUID = "mylutece-wssodatabase.ldap.dn.attributeName.wssoGuid";
73      private static final String PROPERTY_DN_ATTRIBUTE_FAMILY_NAME = "mylutece-wssodatabase.ldap.dn.attributeName.familyName";
74      private static final String PROPERTY_DN_ATTRIBUTE_GIVEN_NAME = "mylutece-wssodatabase.ldap.dn.attributeName.givenName";
75      private static final String PROPERTY_DN_ATTRIBUTE_EMAIL = "mylutece-wssodatabase.ldap.dn.attributeName.email";
76      private static final String ATTRIBUTE_GUID = AppPropertiesService.getProperty( PROPERTY_DN_ATTRIBUTE_GUID );
77      private static final String ATTRIBUTE_FAMILY_NAME = AppPropertiesService.getProperty( PROPERTY_DN_ATTRIBUTE_FAMILY_NAME );
78      private static final String ATTRIBUTE_GIVEN_NAME = AppPropertiesService.getProperty( PROPERTY_DN_ATTRIBUTE_GIVEN_NAME );
79      private static final String ATTRIBUTE_EMAIL = AppPropertiesService.getProperty( PROPERTY_DN_ATTRIBUTE_EMAIL );
80  
81      /* comparator for sorting - date ascendant order */
82      private static final Comparator COMPARATOR_USER = new Comparator(  )
83          {
84              public int compare( Object obj1, Object obj2 )
85              {
86                  WssoUser user1 = (WssoUser) obj1;
87                  WssoUser user2 = (WssoUser) obj2;
88  
89                  int nOrder = user1.getLastName(  ).toUpperCase(  ).compareTo( user2.getLastName(  ).toUpperCase(  ) );
90  
91                  if ( nOrder == 0 )
92                  {
93                      nOrder = user1.getFirstName(  ).toUpperCase(  ).compareTo( user2.getFirstName(  ).toUpperCase(  ) );
94  
95                      if ( nOrder == 0 )
96                      {
97                          nOrder = user1.getEmail(  ).toUpperCase(  ).compareTo( user2.getEmail(  ).toUpperCase(  ) );
98                      }
99                  }
100 
101                 return nOrder;
102             }
103         };
104 
105     /**
106      * Search controls for the user entry search
107      */
108     private SearchControls _scUserSearchControls;
109 
110     /**
111      *
112      */
113     public LdapBrowser(  )
114     {
115     }
116 
117     /**
118      * Returns a list of users corresponding to the given parameters. An empty
119      * parameter is remplaced by the wildcard (*)
120      * @param strParameterLastName Users last name
121      * @param strParameterFirstName Users first name
122      * @param strParameterEmail Users email
123      * @return the list of users
124      */
125     public Collection getUserList( String strParameterLastName, String strParameterFirstName, String strParameterEmail )
126     {
127         ArrayList userList = new ArrayList(  );
128         SearchResult sr = null;
129         Object[] messageFormatParam = new Object[3];
130         String[] messageFormatFilter = new String[3];
131 
132         DirContext context = null;
133 
134         messageFormatParam[0] = checkSyntax( strParameterLastName );
135         messageFormatParam[1] = checkSyntax( strParameterFirstName );
136         messageFormatParam[2] = checkSyntax( strParameterEmail );
137 
138         messageFormatFilter[0] = getUserDnSearchFilterByCriteriaSn(  );
139         messageFormatFilter[1] = getUserDnSearchFilterByCriteriaGivenname(  );
140         messageFormatFilter[2] = getUserDnSearchFilterByCriteriaMail(  );
141 
142         String strUserSearchFilter = buildRequest( messageFormatFilter, messageFormatParam );
143 
144         try
145         {
146             _scUserSearchControls = new SearchControls(  );
147             _scUserSearchControls.setSearchScope( getUserDnSearchScope(  ) );
148             _scUserSearchControls.setReturningObjFlag( true );
149             _scUserSearchControls.setCountLimit( 0 );
150 
151             context = LdapUtil.getContext( getInitialContextProvider(  ), getProviderUrl(  ), getBindDn(  ),
152                     getBindPassword(  ) );
153 
154             NamingEnumeration userResults = LdapUtil.searchUsers( context, strUserSearchFilter,
155                     getUserDnSearchBase(  ), "", _scUserSearchControls );
156 
157             while ( ( userResults != null ) && userResults.hasMore(  ) )
158             {
159                 sr = (SearchResult) userResults.next(  );
160 
161                 Attributes attributes = sr.getAttributes(  );
162                 String strWssoId = "";
163 
164                 if ( attributes.get( ATTRIBUTE_GUID ) != null )
165                 {
166                     strWssoId = attributes.get( ATTRIBUTE_GUID ).get(  ).toString(  );
167                 }
168 
169                 String strLastName = "";
170 
171                 if ( attributes.get( ATTRIBUTE_FAMILY_NAME ) != null )
172                 {
173                     strLastName = attributes.get( ATTRIBUTE_FAMILY_NAME ).get(  ).toString(  );
174                 }
175 
176                 String strFirstName = "";
177 
178                 if ( attributes.get( ATTRIBUTE_GIVEN_NAME ) != null )
179                 {
180                     strFirstName = attributes.get( ATTRIBUTE_GIVEN_NAME ).get(  ).toString(  );
181                 }
182 
183                 String strEmail = "";
184 
185                 if ( attributes.get( ATTRIBUTE_EMAIL ) != null )
186                 {
187                     strEmail = attributes.get( ATTRIBUTE_EMAIL ).get(  ).toString(  );
188                 }
189 
190                 WssoUser user = new WssoUser(  );
191                 user.setGuid( strWssoId );
192                 user.setLastName( strLastName );
193                 user.setFirstName( strFirstName );
194                 user.setEmail( strEmail );
195                 userList.add( user );
196             }
197 
198             Collections.sort( userList, COMPARATOR_USER );
199 
200             return userList;
201         }
202         catch ( CommunicationException e )
203         {
204             AppLogService.error( "Error while searching for users '" + "' with search filter : " +
205                 getDebugInfo( strUserSearchFilter ), e );
206 
207             return null;
208         }
209         catch ( NamingException e )
210         {
211             AppLogService.error( "Error while searching for users ", e );
212 
213             return null;
214         }
215         finally
216         {
217             try
218             {
219                 LdapUtil.freeContext( context );
220             }
221             catch ( NamingException naming )
222             {
223                 AppLogService.error( naming.getMessage(  ), naming );
224             }
225         }
226     }
227 
228     /**
229      * Return a user given its guid
230      * @param strId the guid
231      * @return the corresponding user
232      */
233     public WssoUser getUserPublicData( String strId )
234     {
235         WssoUser user = null;
236         SearchResult sr = null;
237         Object[] messageFormatParam = new Object[1];
238 
239         DirContext context = null;
240 
241         messageFormatParam[0] = strId;
242 
243         String strUserSearchFilter = MessageFormat.format( getUserDnSearchFilterByGUID(  ), messageFormatParam );
244 
245         try
246         {
247             _scUserSearchControls = new SearchControls(  );
248             _scUserSearchControls.setSearchScope( getUserDnSearchScope(  ) );
249             _scUserSearchControls.setReturningObjFlag( true );
250             _scUserSearchControls.setCountLimit( 0 );
251 
252             context = LdapUtil.getContext( getInitialContextProvider(  ), getProviderUrl(  ), getBindDn(  ),
253                     getBindPassword(  ) );
254 
255             NamingEnumeration userResults = LdapUtil.searchUsers( context, strUserSearchFilter,
256                     getUserDnSearchBase(  ), "", _scUserSearchControls );
257 
258             int count = 0;
259 
260             while ( ( userResults != null ) && userResults.hasMore(  ) )
261             {
262                 sr = (SearchResult) userResults.next(  );
263 
264                 Attributes attributes = sr.getAttributes(  );
265                 String strWssoId = "";
266 
267                 if ( attributes.get( ATTRIBUTE_GUID ) != null )
268                 {
269                     strWssoId = attributes.get( ATTRIBUTE_GUID ).get(  ).toString(  );
270                 }
271 
272                 String strLastName = "";
273 
274                 if ( attributes.get( ATTRIBUTE_FAMILY_NAME ) != null )
275                 {
276                     strLastName = attributes.get( ATTRIBUTE_FAMILY_NAME ).get(  ).toString(  );
277                 }
278 
279                 String strFirstName = "";
280 
281                 if ( attributes.get( ATTRIBUTE_GIVEN_NAME ) != null )
282                 {
283                     strFirstName = attributes.get( ATTRIBUTE_GIVEN_NAME ).get(  ).toString(  );
284                 }
285 
286                 String strEmail = "";
287 
288                 if ( attributes.get( ATTRIBUTE_EMAIL ) != null )
289                 {
290                     strEmail = attributes.get( ATTRIBUTE_EMAIL ).get(  ).toString(  );
291                 }
292 
293                 user = new WssoUser(  );
294                 user.setGuid( strWssoId );
295                 user.setLastName( strLastName );
296                 user.setFirstName( strFirstName );
297                 user.setEmail( strEmail );
298                 count++;
299             }
300 
301             // More than one user found (failure)
302             if ( count > 1 )
303             {
304                 AppLogService.error( "More than one entry in the directory for id " + strId );
305 
306                 return null;
307             }
308 
309             return user;
310         }
311         catch ( CommunicationException e )
312         {
313             AppLogService.error( "Error while searching for users '" + "' with search filter : " +
314                 getDebugInfo( strUserSearchFilter ), e );
315 
316             return null;
317         }
318         catch ( NamingException e )
319         {
320             AppLogService.error( "Error while searching for users ", e );
321 
322             return null;
323         }
324         finally
325         {
326             try
327             {
328                 LdapUtil.freeContext( context );
329             }
330             catch ( NamingException naming )
331             {
332                 AppLogService.error( naming.getMessage(  ), naming );
333             }
334         }
335     }
336 
337     /**
338      * Replace the null string or empty string by the wilcard
339      * @param in String to check
340      * @return The given string, or a wilcard if the given string is null or
341      *         empty
342      */
343     private String checkSyntax( String in )
344     {
345         return ( ( ( in == null ) || ( in.equals( "" ) ) ) ? "*" : in );
346     }
347 
348     /**
349      * Return info for debugging
350      * @param strUserSearchFilter User search filter
351      * @return the user search filter
352      */
353     private String getDebugInfo( String strUserSearchFilter )
354     {
355         StringBuffer sb = new StringBuffer(  );
356         sb.append( "userBase : " );
357         sb.append( getUserDnSearchBase(  ) );
358         sb.append( "\nuserSearch : " );
359         sb.append( strUserSearchFilter );
360 
361         return sb.toString(  );
362     }
363 
364     /**
365      * Get the initial context provider from the properties
366      * @return the initial context provider
367      */
368     private String getInitialContextProvider(  )
369     {
370         return AppPropertiesService.getProperty( PROPERTY_INITIAL_CONTEXT_PROVIDER );
371     }
372 
373     /**
374      * Get the provider url from the properties
375      * @return the provider url
376      */
377     private String getProviderUrl(  )
378     {
379         return AppPropertiesService.getProperty( PROPERTY_PROVIDER_URL );
380     }
381 
382     /**
383      * Get the base user dn from the properties
384      * @return the dns search base
385      */
386     private String getUserDnSearchBase(  )
387     {
388         return AppPropertiesService.getProperty( PROPERTY_USER_DN_SEARCH_BASE );
389     }
390 
391     /**
392      * Get the filter for search by guid
393      * @return the user dn search
394      */
395     private String getUserDnSearchFilterByGUID(  )
396     {
397         return AppPropertiesService.getProperty( PROPERTY_USER_DN_SEARCH_FILTER_BY_GUID );
398     }
399 
400     /**
401      * Get the filter for search by sn
402      * @return the user dn search
403      */
404     private String getUserDnSearchFilterByCriteriaSn(  )
405     {
406         return AppPropertiesService.getProperty( PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_SN );
407     }
408 
409     /**
410      * Get the filter for search by givenname
411      * @return the user dn search
412      */
413     private String getUserDnSearchFilterByCriteriaGivenname(  )
414     {
415         return AppPropertiesService.getProperty( PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_GIVENNAME );
416     }
417 
418     /**
419      * Get the filter for search by mail
420      * @return the user dn search
421      */
422     private String getUserDnSearchFilterByCriteriaMail(  )
423     {
424         return AppPropertiesService.getProperty( PROPERTY_USER_DN_SEARCH_FILTER_BY_CRITERIA_MAIL );
425     }
426 
427     /**
428      * Get the user dn search scope
429      * @return the user dn search
430      */
431     private int getUserDnSearchScope(  )
432     {
433         String strSearchScope = AppPropertiesService.getProperty( PROPERTY_USER_SUBTREE );
434 
435         if ( strSearchScope.equalsIgnoreCase( "true" ) )
436         {
437             return SearchControls.SUBTREE_SCOPE;
438         }
439 
440         return SearchControls.ONELEVEL_SCOPE;
441     }
442 
443     /**
444      * get the bind dn
445      * @return the bind dn
446      */
447     private String getBindDn(  )
448     {
449         return AppPropertiesService.getProperty( PROPERTY_BIND_DN );
450     }
451 
452     /**
453      * Get the bing password
454      * @return bind password
455      */
456     private String getBindPassword(  )
457     {
458         return AppPropertiesService.getProperty( PROPERTY_BIND_PASSWORD );
459     }
460 
461     /**
462      * build request for search by sn, givenname and mail
463      * @param messageFormatFilter message format filter
464      * @param messageFormatParam message format param
465      * @return the user dn search
466      */
467     private String buildRequest( String[] messageFormatFilter, Object[] messageFormatParam )
468     {
469         StringBuffer strUserSearchFilter = new StringBuffer( "(&" );
470 
471         for ( int i = 0; i < messageFormatParam.length; i++ )
472         {
473             if ( !messageFormatParam[i].equals( "*" ) )
474             {
475                 strUserSearchFilter.append( MessageFormat.format( messageFormatFilter[i], messageFormatParam ) );
476             }
477         }
478 
479         strUserSearchFilter.append( ")" );
480 
481         return strUserSearchFilter.toString(  );
482     }
483 }