View Javadoc

1   /*
2    * GecosMap.java
3    *
4    * Created on March 25, 2004, 4:11 PM
5    */
6   
7   package gov.bnl.gums.account;
8   
9   import gov.bnl.gums.GUMS;
10  import gov.bnl.gums.account.NISClient;
11  
12  import java.io.PrintStream;
13  import java.util.ArrayList;
14  import java.util.Collection;
15  import java.util.Date;
16  import java.util.Hashtable;
17  import java.util.Iterator;
18  import java.util.List;
19  import java.util.Map;
20  
21  import org.apache.commons.collections.MultiHashMap;
22  import org.apache.commons.collections.MultiMap;
23  import org.apache.log4j.Logger;
24  
25  /** 
26   * Retrieves the map from the NIS server and provide a logic to match name and
27   * surname to an account.
28   *
29   * @author  Gabriele Carcassi, Jay Packard
30   */
31  public class GecosMap {
32      private Logger log = Logger.getLogger(NISClient.class);
33      private Logger gumsAdminLog = Logger.getLogger(GUMS.gumsAdminLogName);
34      private Map accountToGecos = new Hashtable();
35      private Map accountToName = new Hashtable();
36      private Map accountToSurname = new Hashtable();
37      private MultiMap nameToAccount = new MultiHashMap();
38      private MultiMap surnameToAccount = new MultiHashMap();
39      private Date lastUpdate = null;
40      private long expiration = 60*60*1000;
41  
42      public void addEntry(String account, String gecos) {
43          String name = retrieveName(gecos);
44          String surname = retrieveSurname(gecos);
45          log.trace("Adding user '" + account + "': GECOS='" + gecos + "' name='" + name + "' surname='" + surname + "'");
46          accountToGecos.put(account, gecos);
47          if (name != null) {
48              accountToName.put(account, name);
49              nameToAccount.put(name.toLowerCase(), account);
50          }
51          accountToSurname.put(account, surname);
52          surnameToAccount.put(surname.toLowerCase(), account);
53          lastUpdate = new Date();
54      }
55      
56      public String findAccount(String name, String surname) {
57          Collection accountsWithName = (Collection) nameToAccount.get(name.toLowerCase());
58          Collection accountsWithSurname = (Collection) surnameToAccount.get(surname.toLowerCase());
59          log.trace("Account matching. Name: " + accountsWithName + "- Surname: " + accountsWithSurname);
60          if ((accountsWithName != null) && (accountsWithSurname != null)) {
61              // Accounts for both name and surname were found
62              List commonAccounts = new ArrayList(accountsWithName);
63              commonAccounts.retainAll(accountsWithSurname);
64              if (commonAccounts.size() == 1) {
65                  // Only one account matching both name and surname was found
66                  // Pretty likely is the correct one
67                  String account = (String) commonAccounts.get(0);
68                  log.trace("NIS account Name/Surname single match. Name: " + name + " - Surname: " + surname + " - account: " + account);
69                  return account;
70              } else if (commonAccounts.size() > 1) {
71                  // More than one account with the matching account has been found
72                  // It might be that only one account is really for the user, and the
73                  // other are group/system accounts
74                  // Check whether only one account contains the surname
75                  Iterator iter = commonAccounts.iterator();
76                  String matchingAccount = null;
77                  while (iter.hasNext()) {
78                      String account = (String) iter.next();
79                      if (account.indexOf(surname.toLowerCase()) != -1) {
80                          if (matchingAccount == null) {
81                              matchingAccount = account;
82                          } else {
83                              // Two accounts matched. Can't decide, return null.
84                              log.trace("NIS account Name/Surname multiple match, multiple account with surname." +
85                              " Name: " + name + " - Surname: " + surname + " - account: not defined");
86                              gumsAdminLog.debug("NIS/LDAP mapping: couldn't find single match for surname='" + surname + "' name='" + name + "'. Undecided between " + commonAccounts);
87                              return null;
88                          }
89                      }
90                  }
91                  if (matchingAccount != null) {
92                      // Only one matching account was found. There is a chance
93                      // this is the right account
94                      log.trace("NIS account Name/Surname multiple match, single account with surname." +
95                      " Name: " + name + " - Surname: " + surname + " - account: " + matchingAccount);
96                      return matchingAccount;
97                  }
98                  // Can't decide which account is the correct one
99                  log.trace("NIS account Name/Surname multiple match, no account with surname." +
100                 " Name: " + name + " - Surname: " + surname + " - account: not defined");
101                 gumsAdminLog.debug("NIS/LDAP mapping: couldn't find single match for surname='" + surname + "' name='" + name + "'. Undecided between " + commonAccounts);
102                 return null;
103             }
104             // Common Accounts has no items, disregarding the name
105         }
106         if (accountsWithSurname != null) {
107             if (accountsWithSurname.size() == 1) {
108                 String account = (String) accountsWithSurname.iterator().next();
109                 log.trace("NIS account Surname single match, no match on Name. Name: " + name + " - Surname: " + surname + " - account: " + account);
110                 return account;
111             } else {
112                 log.trace("NIS account Surname multiple match, no match on Name. Name: " + name + " - Surname: " + surname + " - account: undefined");
113                 gumsAdminLog.debug("NIS/LDAP mapping: couldn't find single match for surname='" + surname + "' name='" + name + "'. Undecided between " + accountsWithSurname);
114                 return null;
115             }
116         }
117         log.trace("NIS account no match on Surname. Name: " + name + " - Surname: " + surname + " - account: undefined");
118         // Try reversing name and surname
119         accountsWithName = (Collection) nameToAccount.get(surname.toLowerCase());
120         accountsWithSurname = (Collection) surnameToAccount.get(name.toLowerCase());
121         if ((accountsWithName != null) && (accountsWithSurname != null)) {
122             // Accounts for both name and surname were found
123             List commonAccounts = new ArrayList(accountsWithName);
124             commonAccounts.retainAll(accountsWithSurname);
125             if (commonAccounts.size() == 1) {
126                 // Only one account matching both name and surname was found
127                 // Pretty likely is the correct one
128                 String account = (String) commonAccounts.get(0);
129                 log.trace("NIS account inverted Name/Surname single match. Name: " + surname + " - Surname: " + name + " - account: " + account);
130                 return account;
131             }
132         }
133         return null;
134     }
135     
136     /**
137      * How long the map will be valid since the last change.
138      * <p>
139      * By default is 60*60*1000 (one hour).
140      * @return Time of validity in ms.
141      */
142     public long getExpiration() {
143 
144         return this.expiration;
145     }
146     
147     public boolean isValid() {
148         if (lastUpdate == null) return false;
149         if ((System.currentTimeMillis() - lastUpdate.getTime()) > expiration) return false;
150         return true;
151     }
152     
153     public void printMaps(PrintStream out) {
154         out.println("account to gecos map");
155         out.println("---------------------");
156         out.println();
157         Iterator accounts = accountToGecos.keySet().iterator();
158         while (accounts.hasNext()) {
159             String account = (String) accounts.next();
160             String gecos = (String) accountToGecos.get(account);
161             String name = (String) accountToName.get(account);
162             String surname = (String) accountToSurname.get(account);
163             out.print(account);
164             for (int n = account.length(); n < 15; n++) {
165                 out.print(' ');
166             }
167             out.print(gecos);
168             for (int n = gecos.length(); n < 30; n++) {
169                 out.print(' ');
170             }
171             out.print(name);
172             for (int n = name.length(); n < 15; n++) {
173                 out.print(' ');
174             }
175             out.println(surname);
176         }
177     }
178     
179     /**
180      * How long the map will be valid since the last change.
181      * @param expiration Time of validity in ms.
182      */
183     public void setExpiration(long expiration) {
184 
185         this.expiration = expiration;
186     }
187     
188     private void printMap(PrintStream out, Map map, int offset) {
189         Iterator accounts = map.keySet().iterator();
190         while (accounts.hasNext()) {
191             String account = (String) accounts.next();
192             String gecos = (String) map.get(account);
193             out.print(account);
194             for (int n = account.length(); n < offset; n++) {
195                 out.print(' ');
196             }
197             out.println(gecos);
198             
199         }
200     }
201 
202     private String retrieveName(String gecos) {
203         gecos = gecos.trim();
204         int comma = gecos.indexOf(',');
205         if (comma != -1) {
206             gecos = gecos.substring(0, comma);
207         }
208         int index = gecos.lastIndexOf(' ');
209         if (index == -1) return "";
210         return gecos.substring(0, gecos.indexOf(' '));
211     }
212 
213     private String retrieveSurname(String gecos) {
214         gecos = gecos.trim();
215         int comma = gecos.indexOf(',');
216         if (comma != -1) {
217             gecos = gecos.substring(0, comma);
218         }
219         int index = gecos.lastIndexOf(' ');
220         if (index == -1) return gecos;
221         return gecos.substring(gecos.lastIndexOf(' ')+1);
222     }
223     
224 }