View Javadoc

1   /*
2    * VOMSGroup.java
3    *
4    * Created on May 25, 2004, 10:20 AM
5    */
6   
7   package gov.bnl.gums;
8   
9   import java.net.*;
10  import java.util.*;
11  import org.apache.commons.logging.Log;
12  import org.apache.commons.logging.LogFactory;
13  import org.edg.security.voms.service.admin.*;
14  
15  /*** A group of users residing on a VOMS vo database. This class is able to 
16   * import a list of users from a VOMS server. It will store to a local
17   * medium through the UserGroupDB interface. It also manages the caching from
18   * the local database.
19   * <p>
20   * The authentication is done through the proxy, or a certificate/key/password
21   * combination. The parameters are to be set externally as system properties.
22   * The proxy can be set through "gridProxyFile" property. Other properties
23   * are "sslCertfile", "sslKey", "sslKeyPasswd" and "sslCAFiles". More documentation
24   * can be found in the documentation of the edg trustmanager  
25   *
26   * @todo Should refactor with LDAPGroup, and provide a PersistanceCachedGroup
27   * since they both share local site buffering functionality
28   * @author  Gabriele Carcassi
29   */
30  public class VOMSGroup implements UserGroup {
31      private Log log = LogFactory.getLog(VOMSGroup.class);
32      private Log resourceAdminLog = LogFactory.getLog(GUMS.resourceAdminLog);
33      
34      private UserGroupDB db;
35      private String name;
36      private PersistenceFactory persistanceFactory;
37      private String url;
38      private String fqan;
39      private List matchFQANValues = Arrays.asList(new String[] {"ignore", "vo", "group", "exact"});
40      private String matchFQAN = "exact";
41      
42      /***
43       * Holds value of property sslKey.
44       */
45      private String sslKey;
46      
47      /***
48       * Holds value of property sslCertfile.
49       */
50      private String sslCertfile;
51      
52      /***
53       * Holds value of property sslCAFiles.
54       */
55      private String sslCAFiles;
56      
57      /***
58       * Holds value of property sslKeyPasswd.
59       */
60      private String sslKeyPasswd;
61      
62      /***
63       * Holds value of property voGroup.
64       */
65      private String voGroup;
66      
67      /***
68       * Holds value of property voRole.
69       */
70      private String voRole;
71      
72      public java.util.List getMemberList() {
73          return db.retrieveMembers();
74      }
75      
76      public String getName() {
77          return name;
78      }
79      
80      public boolean isInGroup(GridUser user) {
81          // If the user comes in without FQAN, either we accept proxies without
82          // it or we kick him out right away
83          if ((user.getVoFQAN() == null) && !isAcceptProxyWithoutFQAN()) {
84              
85              // FIXME To achieve complete backward compatibility with GUMS 1.0,
86              // if the voGroup is null and the user comes in with no Proxy
87              // we still allow him in.
88              // We should remove this in versions after 1.1
89              if ((voGroup == null) && (voRole == null)) {
90                  return db.isMemberInGroup(user);
91              }
92              return false;
93          }
94          
95          // If the user comes in wihout FQAN, but we accept proxies without it,
96          // we simply check whether the DN is in the database
97          if ((user.getVoFQAN() == null) && isAcceptProxyWithoutFQAN()) {
98              if (db.isMemberInGroup(new GridUser(user.getCertificateDN(), fqan)))
99                  return true;
100             return false;
101         }
102         
103         // At this point, the user has FQAN
104         // To avoid a query on the db, we check if the fqan matches first
105 
106         // If we have an exact match, fqan has to be the same
107         if ("exact".equals(matchFQAN)) {
108             if (!user.getVoFQAN().toString().equals(fqan))
109                 return false;
110         }
111 
112         // If we match the vo, we check the vo is the same
113         if ("vo".equals(matchFQAN)) {
114             FQAN theFQAN = new FQAN(fqan);
115             if (!user.getVoFQAN().getVo().equals(theFQAN.getVo()))
116                 return false;
117         }
118         
119         // If we match the group, we make sure the VO starts with the group
120         if ("group".equals(matchFQAN)) {
121             if (!user.getVoFQAN().toString().startsWith(voGroup))
122                 return false;
123         }
124 
125         // FQAN matches, let's look up if the DN is in the db
126         // If not, he's kicked out
127         return db.isMemberInGroup(new GridUser(user.getCertificateDN(), fqan));
128     }
129     
130     public void updateMembers() {
131         db.loadUpdatedList(retrieveMembers());
132     }
133     
134     /***
135      * Returns the address of the VOMS server to contact.
136      * @return The address of the VOMS server (i.e. https://voms.myste.org:8443/edg-voms-admin/myvo/services/VOMSAdmin)
137      */
138     public String getUrl() {
139         return url;
140     }
141     
142     /***
143      * Changes the address of the VOMS server to contact. The address of the server
144      * is really the address of the Web service components. If you go to that address,
145      * the AXIS servlet has to reply.
146      * @param url The address of the VOMS server (i.e. https://voms.myste.org:8443/edg-voms-admin/myvo/services/VOMSAdmin)
147      */
148     public void setUrl(String url) {
149         this.url = url;
150     }
151     
152     private List retrieveMembers() {
153         Properties p = System.getProperties();
154         try {
155             setProperties();
156             log.debug("SSL properties: sslCAFiles='" + System.getProperty("sslCAFiles") + 
157             "' sslCertfile='" + System.getProperty("sslCertfile") +
158             "' sslKey='" + System.getProperty("sslKey") +
159             "' sslKeyPasswd set:" + (System.getProperty("sslKeyPasswd")!= null) +"'"); 
160             log.info("Retrieve members: url='" + url + "' name='" + name + "' persistanceFactory='" + persistanceFactory.getName() + "'");
161             System.setProperty("axis.socketSecureFactory", "org.edg.security.trustmanager.axis.AXISSocketFactory");
162             VOMSAdminServiceLocator locator = new VOMSAdminServiceLocator();
163             URL vomsUrl = new URL(url);
164             VOMSAdmin voms = locator.getVOMSAdmin(vomsUrl);
165             org.edg.security.voms.service.User[] users = null;
166             if (voRole == null) {
167                 users = voms.listMembers(getVoGroup());
168             } else {
169                 users = voms.listUsersWithRole(getVoGroup(), "Role=" + getVoRole());
170             }
171             if (users.length > 0) {
172                 log.trace("Retrieved " + users.length + " users. First is: '" + users[0].getDN());
173             } else {
174                 log.trace("Retrieved no users.");
175             }
176             List entries = new ArrayList();
177             for (int n=0; n< users.length; n++) {
178                 entries.add(new GridUser(users[n].getDN(), fqan));
179             }
180             System.setProperties(p);
181             if (entries.isEmpty()) {
182                 resourceAdminLog.warn("The following group returned no members: " + this);
183             }
184             return entries;
185         } catch (Throwable e) {
186             log.error("Couldn't retrieve VOMS users: ", e);
187             //gumsAdmin.("Couldn't retrieve ");
188             System.setProperties(p);
189             throw new RuntimeException("Couldn't retrieve users from VOMS server: " + e.getMessage(), e);
190         }
191     }
192     
193     private void setProperties() {
194         log.debug("SSL properties: sslCAFiles='" + getSslCAFiles() +"' sslCertfile='" + getSslCertfile() +"' sslKey='" + getSslKey() + "' sslKeyPasswd set:" + (getSslKeyPasswd()!= null) +"'"); 
195         if (getSslCAFiles() != null) {
196             System.setProperty("sslCAFiles", getSslCAFiles());
197         }
198         if (getSslCertfile() != null) {
199             System.setProperty("sslCertfile", getSslCertfile());
200         }
201         if (getSslKey() != null) {
202             System.setProperty("sslKey", getSslKey());
203         }
204         if (getSslKeyPasswd() != null) {
205             System.setProperty("sslKeyPasswd", getSslKeyPasswd());
206         }
207     }
208     
209     public String getPersistenceFactory() {
210         return persistanceFactory.getName();
211     }
212     
213     public void setPersistence(PersistenceFactory persistanceFactory, String name) {
214         this.persistanceFactory = persistanceFactory;
215         this.name = name;
216         db = persistanceFactory.retrieveUserGroupDB(name);
217     }  
218     
219     /***
220      * Returns the location of the key to be used during the connection.
221      * @return The location of the key (i.e. /etc/grid-security/hostkey.pem)
222      */
223     public String getSslKey() {
224         return this.sslKey;
225     }
226     
227     /***
228      * Changes the location of the private key used to connect to the VOMS server.
229      * @param sslKey The location of the key (i.e. /etc/grid-security/hostkey.pem)
230      */
231     public void setSslKey(String sslKey) {
232         this.sslKey = sslKey;
233     }
234     
235     /***
236      * Returns the location of the certificated used to connect to the VOMS server.
237      * @return The location of the certificate (i.e. /etc/grid-security/hostcert.pem)
238      */
239     public String getSslCertfile() {
240         return this.sslCertfile;
241     }
242     
243     /***
244      * Changes the location of the certificated used to connect to the VOMS server.
245      * @param sslCertfile The location of the certificate (i.e. /etc/grid-security/hostcert.pem)
246      */
247     public void setSslCertfile(String sslCertfile) {
248         this.sslCertfile = sslCertfile;
249     }
250     
251     /***
252      * Returns the location of the Certificate Authority certificates used to connect to the VOMS server.
253      * @return The location of the CA certificates (i.e. /etc/grid-security/certificates/*.0)
254      */
255     public String getSslCAFiles() {
256         return this.sslCAFiles;
257     }
258     
259     /***
260      * Changes the location of the Certificate Authority certificates used to connect to the VOMS server.
261      * @param sslCAFiles The location of the CA certificates (i.e. /etc/grid-security/certificates/*.0)
262      */
263     public void setSslCAFiles(String sslCAFiles) {
264         this.sslCAFiles = sslCAFiles;
265     }
266     
267     /***
268      * Returns the private key password used to connect to the VOMS server.
269      * @return The password for the private key
270      */
271     public String getSslKeyPasswd() {
272         return this.sslKeyPasswd;
273     }
274     
275     /***
276      * Changes the private key password used to connect to the VOMS server.
277      * @param sslKeyPasswd The password for the private key
278      */
279     public void setSslKeyPasswd(String sslKeyPasswd) {
280         this.sslKeyPasswd = sslKeyPasswd;
281     }
282     
283     
284     public String toString() {
285         return "VOMSGroup: "+url+" - voGroup='" + getVoGroup() + "' - voRole='" + getVoRole() + "' - sslCAFiles='" + getSslCAFiles() +"' sslCertfile='" + getSslCertfile() +"' sslKey='" + getSslKey() + "' sslKeyPasswd=" + ((getSslKeyPasswd()!= null) ? "[set]" : "[not set]");
286     }
287     
288     /***
289      * Returns the group to be retrieved from the VO.
290      * @return The group in the VOMS (i.e. /atlas/usatlas)
291      */
292     public String getVoGroup() {
293         return this.voGroup;
294     }
295     
296     /***
297      * Changes the group to be retrieved from the VO.
298      * @param voGroup The group in the VOMS (i.e. /atlas/usatlas)
299      */
300     public void setVoGroup(String voGroup) {
301         this.voGroup = voGroup;
302         prepareFQAN();
303     }
304     
305     /***
306      * Changes the role to be retrieved within the VO group.
307      * @return The role name in the VOMS server (i.e. myrole), or null for no role
308      */
309     public String getVoRole() {
310         return this.voRole;
311     }
312     
313     /***
314      * Changes the role to be retrieved within the VO group.
315      * @param voRole The role name in the VOMS server (i.e. myrole), or null for no role
316      */
317     public void setVoRole(String voRole) {
318         this.voRole = voRole;
319         prepareFQAN();
320     }
321     
322     private void prepareFQAN() {
323         if (voGroup == null) {
324             fqan = null;
325         } else {
326             if (voRole == null) {
327                 fqan = voGroup;
328             } else {
329                 fqan = voGroup + "/Role=" + voRole;
330             }
331         }
332     }
333     
334     /***
335      * Tells whether the FQAN should be used to match the proxy or not. If set to false,
336      * the FQAN has to be present (i.e. won't accept non VOMS proxy) and has to match
337      * the one defined by the group. If set to true, the FQAN is not looked at, making
338      * all proxies (non VOMS and VOMS proxy with different FQAN) match as long as the
339      * DN matches. Setting true makes the behaviour similar to the one of the
340      * grid-mapfile.
341      * @return False if FQAN is used during the match
342      * @deprecated As of GUMS 1.1, use matchFQAN and acceptProxyWithoutFQAN
343      */
344     public boolean isIgnoreFQAN() {
345         return "ignore".equals(matchFQAN);
346     }
347     
348     /***
349      * Changes the way FQAN is used to match.
350      * @param ignoreFQAN False if FQAN is used during the matchNew value of property ignoreFQAN.
351      * @deprecated As of GUMS 1.1, use matchFQAN and acceptProxyWithoutFQAN
352      */
353     public void setIgnoreFQAN(boolean ignoreFQAN) {
354         resourceAdminLog.warn("The attribute \"ignoreFQAN\" for VOMSGroup is deprecated: use matchFQAN instead. DO NOT MIX ignoreFQAN and matchFQAN.");
355         if (ignoreFQAN) {
356             matchFQAN = "ignore";
357             acceptProxyWithoutFQAN = true;
358         } else {
359             matchFQAN = "exact";
360             acceptProxyWithoutFQAN = false;
361         }
362     }
363 
364     /***
365      * The scheme according to which the FQAN will be matched.
366      * <p>
367      * Possible values are:
368      * <ul>
369      *   <li>exact (default) - the FQAN in the proxy has to be the same as
370      *   what the VOMSGroup is set to. </li>
371      *   <li>group - the FQAN in the proxy has to be the same group, or any
372      *   subgroup; role is ignored.</li>
373      *   <li>vo - the FQAN in the proxy has to be of the same vo.</li>
374      *   <li>ignore - the FQAN in the proxy is completely ignored.</li>
375      * </ul>
376      * @return One of the following:  "ignore", "vo", "group" or "exact".
377      */
378     public String getMatchFQAN() {
379 
380         return this.matchFQAN;
381     }
382 
383     /***
384      * Changes the scheme according to which the FQAN will be matched. See
385      * getMatchFQAN for more details.
386      * @param matchFQAN One of the following:  "ignore", "vo", "group" or "exact".
387      */
388     public void setMatchFQAN(String matchFQAN) {
389         if (!matchFQANValues.contains(matchFQAN)) {
390             throw new IllegalArgumentException("The accepted values for matchFQAN in VOMSGroup are: " + matchFQANValues);
391         }
392 
393         this.matchFQAN = matchFQAN;
394     }
395 
396     /***
397      * Holds value of property acceptProxyWithoutFQAN.
398      */
399     private boolean acceptProxyWithoutFQAN;
400 
401     /***
402      * True if non-VOMS will be accepted. If true, all non-VOMS proxies with a matchin
403      * DN will be matched. VOMS proxies won't be affected by the use of this property.
404      * @return True if group will accept non-VOMS proxies
405      */
406     public boolean isAcceptProxyWithoutFQAN() {
407 
408         return this.acceptProxyWithoutFQAN;
409     }
410 
411     /***
412      * Changes the way non-VOMS proxies are handled.
413      * @param acceptProxyWithoutFQAN True if group will accept non-VOMS proxies
414      */
415     public void setAcceptProxyWithoutFQAN(boolean acceptProxyWithoutFQAN) {
416 
417         this.acceptProxyWithoutFQAN = acceptProxyWithoutFQAN;
418     }
419     
420 }