View Javadoc

1   /*
2    * VOMSUserGroupManager.java
3    *
4    * Created on May 25, 2004, 10:20 AM
5    */
6   
7   package gov.bnl.gums.userGroup;
8   
9   import gov.bnl.gums.FQAN;
10  import gov.bnl.gums.GUMS;
11  import gov.bnl.gums.GridUser;
12  import gov.bnl.gums.configuration.Configuration;
13  import gov.bnl.gums.db.HibernateUserGroupDB;
14  import gov.bnl.gums.db.UserGroupDB;
15  import gov.bnl.gums.persistence.LDAPPersistenceFactory;
16  
17  import java.net.URL;
18  import java.util.*;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory; 
22  import org.edg.security.voms.service.admin.*;
23  
24  /** A group of users residing on a VOMS vo database. This class is able to 
25   * import a list of users from a VOMS server. It will store to a local
26   * medium through the UserGroupDB interface. It also manages the caching from
27   * the local database.
28   * <p>
29   * The authentication is done through the proxy, or a certificate/key/password
30   * combination. The parameters are to be set externally as system properties.
31   * The proxy can be set through "gridProxyFile" property. Other properties
32   * are "sslCertfile", "sslKey", "sslKeyPasswd" and "sslCAFiles". More documentation
33   * can be found in the documentation of the edg trustmanager  
34   *
35   * @todo Should refactor with LDAPGroup, and provide a PersistanceCachedGroup
36   * since they both share local site buffering functionality
37   * @author Gabriele Carcassi, Jay Packard
38   */
39  public class VOMSUserGroup extends UserGroup {
40  	static private final boolean defaultAcceptProxyWithoutFQAN = true;
41  	static private final String defaultMatchFQAN = "ignore";
42  	static private String[] matchFQANTypes = {"exact","vorole","role","vogroup","vo","ignore"};
43  	
44      static public String getTypeStatic() {
45  		return "voms";
46  	}
47      
48      static public List getMatchFQANTypes() {
49  		ArrayList retList = new ArrayList();
50  		for(int i=0; i<matchFQANTypes.length; i++)
51  			retList.add(matchFQANTypes[i]);
52  		return retList;
53  	}
54  
55      private Log log = LogFactory.getLog(VOMSUserGroup.class);
56      private Log resourceAdminLog = LogFactory.getLog(GUMS.resourceAdminLog);
57      private String vomsServer = "";
58      private String voGroup = "";
59      private String role = "";
60      private String fqan = null;
61      private String matchFQAN = defaultMatchFQAN;
62      private String remainderUrl = "";
63  
64  	private boolean acceptProxyWithoutFQAN = defaultAcceptProxyWithoutFQAN;
65      
66      public VOMSUserGroup() {
67      	super();
68      }    
69   
70  	public VOMSUserGroup(Configuration configuration) {
71  		super(configuration);
72  	}
73      
74  	public VOMSUserGroup(Configuration configuration, String name) {
75  		super(configuration, name);
76  	}
77      
78      public UserGroup clone(Configuration configuration) {
79      	VOMSUserGroup userGroup = new VOMSUserGroup(configuration, new String(getName()));
80      	userGroup.setDescription(new String(getDescription()));
81      	userGroup.setAccess(new String(getAccess()));
82      	userGroup.setVomsServer(new String(getVomsServer()));
83      	userGroup.setRole(new String(getRole()));
84      	userGroup.setVoGroup(new String(getVoGroup()));
85      	userGroup.setMatchFQAN(new String(getMatchFQAN()));
86      	userGroup.setRemainderUrl(new String(getRemainderUrl()));
87      	userGroup.setAcceptProxyWithoutFQAN(acceptProxyWithoutFQAN);
88      	return userGroup;
89      }
90      
91      /**
92       * The scheme according to which the FQAN will be matched.
93       * <p>
94       * Possible values are:
95       * <ul>
96       *   <li>exact (default) - role, group, and vo have to match. </li>
97       *   <li>vorole - role and vo have to match.</li>
98       *   <li>role - rolehas to match.</li>
99       *   <li>group, vogroup - group and vo have to match.</li>
100      *   <li>vo - vo has to match.</li>
101      *   <li>ignore - no matching.</li>
102      * </ul>
103      * @return matching type as String.
104      */
105     public String getMatchFQAN() {
106    		return matchFQAN;
107     }
108     
109     public java.util.List getMemberList() {
110         return getVoDB().retrieveMembers();
111     }
112     
113     public String getRemainderUrl() {
114     	return remainderUrl;
115     }
116     
117     public String getType() {
118 		return "voms";
119 	}
120     
121     public String getUrl() {
122     	return getVoObject().getBaseUrl() + remainderUrl;
123     }
124     
125     /**
126      * Get name of VomsServer
127      * @return
128      */
129     public String getVomsServer() {
130     	return vomsServer;
131     }
132     
133     /**
134      * Returns the VO group.
135      * @return The group in the VOMS (i.e. /atlas/usatlas)
136      */
137     public String getVoGroup() {
138         return this.voGroup;
139     }
140     
141     public VOMSAdmin getVOMSAdmin() {
142         try {
143             log.info("VOMS Service Locater: url='" + getUrl() + "'");
144             System.setProperty("axis.socketSecureManager", "org.edg.security.trustmanager.axis.AXISSocketManager");
145             VOMSAdminServiceLocator locator = new VOMSAdminServiceLocator();
146             URL vomsUrl = new URL( getUrl() );
147             log.info("Connecting to VOMS admin at " + vomsUrl);
148             return locator.getVOMSAdmin(vomsUrl);
149         } catch (Throwable e) {
150             log.error("Couldn't get VOMS Admin: ", e);
151             throw new RuntimeException("Couldn't get VOMS Admin: " + e.getMessage(), e);
152         }
153     }    
154     
155     /**
156      * Changes the role.
157      * @return The role name in the VOMS server (i.e. myrole), or "" for no role
158      */
159     public String getRole() {
160         return this.role;
161     }
162     
163     /**
164      * True if non-VOMS will be accepted. If true, all non-VOMS proxies with a matchin
165      * DN will be matched. VOMS proxies won't be affected by the use of this property.
166      * @return True if group will accept non-VOMS proxies
167      */
168     public boolean isAcceptProxyWithoutFQAN() {
169         return this.acceptProxyWithoutFQAN;
170     }
171     
172     /**
173      * Convenience function for "ignore".equals(getmatchFQAN())
174      * @return False if FQAN is used during the match
175      */
176    public boolean isIgnoreFQAN() {
177         return "ignore".equals(matchFQAN);
178     }
179     
180     public boolean isInGroup(GridUser user) {
181         // If the user comes in without FQAN and we don't accept proxies without fqan,
182         // kick him out right away
183         if (user.getVoFQAN()==null && !isAcceptProxyWithoutFQAN())
184             return false;
185         
186         // If the user comes in without FQAN and we accept proxies without it,
187         // we simply check whether the DN is in the database
188         if (user.getVoFQAN()==null && isAcceptProxyWithoutFQAN()) {
189             if (getVoDB().isMemberInGroup(new GridUser(user.getCertificateDN(), fqan)))
190                 return true;
191             return false;
192         }
193         
194         // At this point, the user has FQAN
195         // To avoid a query on the db, we check if the fqan matches first
196 
197         // If we have vorole match, entire fqan has to be the same
198         if ("exact".equals(getMatchFQAN())) {
199             if (!user.getVoFQAN().toString().equals(fqan))
200                 return false;
201         }
202         
203         // If we have a vo-role match, vo and role has to be the same
204         if ("vorole".equals(getMatchFQAN())) {
205         	FQAN theFQAN = new FQAN(fqan);
206             if (!user.getVoFQAN().getVo().equals(theFQAN.getVo()) && !user.getVoFQAN().getRole().equals(theFQAN.getRole()))
207                 return false;
208         }
209         
210         // If we have a role match, role has to be the same
211         if ("role".equals(getMatchFQAN())) {
212         	FQAN theFQAN = new FQAN(fqan);
213             if (!user.getVoFQAN().getRole().equals(theFQAN.getRole()))
214                 return false;
215         }
216         
217         // If we match the group, we make sure the VO starts with the group
218         if ("group".equals(getMatchFQAN()) || "vogroup".equals(getMatchFQAN())) {
219             if (!user.getVoFQAN().toString().startsWith(voGroup))
220                 return false;
221         }
222 
223         // If we match the vo, we check the vo is the same
224         if ("vo".equals(getMatchFQAN())) {
225             FQAN theFQAN = new FQAN(fqan);
226             if (!user.getVoFQAN().getVo().equals(theFQAN.getVo()))
227                 return false;
228         }
229         
230         // FQAN matches, let's look up if the DN is in the db
231         // If not, he's kicked out
232         return getVoDB().isMemberInGroup(new GridUser(user.getCertificateDN(), fqan));
233     }
234 
235     /**
236      * Changes the way non-VOMS proxies are handled.
237      * @param acceptProxyWithoutFQAN True if group will accept non-VOMS proxies
238      */
239     public void setAcceptProxyWithoutFQAN(boolean acceptProxyWithoutFQAN) {
240         this.acceptProxyWithoutFQAN = acceptProxyWithoutFQAN;
241     }
242 
243     /**
244      * Changes the scheme according to which the FQAN will be matched. See
245      * getMatchFQAN for more details.
246      * @param matchFQAN One of the following:  "exact, "vorole, "role", "vogroup", "vo", "ignore". (also "group" for backwards compat.)
247      */
248     public void setMatchFQAN(String matchFQAN) {
249     	boolean found = false;
250     	if (matchFQAN.equals("group"))
251     		matchFQAN = "vogroup";
252     	if (matchFQAN.equals(""))
253     		matchFQAN = "exact";
254     	for (int i=0; i<matchFQANTypes.length; i++)
255     		if (matchFQANTypes[i].equalsIgnoreCase(matchFQAN)) found = true;
256     	if (!found)
257     		throw new RuntimeException("Invalid match FQAN string: "+matchFQAN);
258         this.matchFQAN = matchFQAN;
259     }
260     
261     public void setRemainderUrl(String remainderUrl) {
262     	this.remainderUrl = remainderUrl;
263     }
264 
265     /**
266      * Set name of VOMS Server
267      * @param vo
268      */
269     public void setVomsServer(String vomsServer) {
270     	this.vomsServer = vomsServer;
271     }
272     
273     /**
274      * Changes the VO group.
275      * @param voGroup The group in the VOMS (i.e. /atlas/usatlas)
276      */
277     public void setVoGroup(String voGroup) {
278         this.voGroup = voGroup;
279         prepareFQAN();
280     }
281     
282     /**
283      * Changes the role.
284      * @param role The role in the VOMS (i.e.production)
285      */
286     public void setRole(String role) {
287         this.role = role;
288         prepareFQAN();
289     }
290 
291     public String toString() {
292         return "VOMSGroup: remainderUrl='" + remainderUrl + "' - voGroup='" + getVoGroup() + "' - role='" + getRole() + "'";
293     }
294     
295     public String toString(String bgColor) {
296     	return "<td bgcolor=\""+bgColor+"\"><a href=\"userGroups.jsp?command=edit&name=" + getName() + "\">" + getName() + "</a></td><td bgcolor=\""+bgColor+"\">" + getType() + "</td><td bgcolor=\""+bgColor+"\">" + matchFQAN + "</td><td bgcolor=\""+bgColor+"\">" + acceptProxyWithoutFQAN + "</td><td bgcolor=\""+bgColor+"\">" + voGroup + "&nbsp;</td><td bgcolor=\""+bgColor+"\">" + role + "&nbsp;</td>";
297     }
298 
299     public String toXML() {
300     	String retStr = "\t\t<vomsUserGroup\n"+
301 		"\t\t\tname='"+getName()+"'\n"+
302 		"\t\t\taccess='"+accessTypes[accessIndex]+"'\n" +
303 		"\t\t\tdescription='"+getDescription()+"'\n"+
304         "\t\t\tvomsServer='"+vomsServer+"'\n";
305     	if (!remainderUrl.equals(""))
306     		retStr += "\t\t\tremainderUrl='"+remainderUrl+"'\n";
307    		retStr += "\t\t\tmatchFQAN='"+matchFQAN+"'\n";
308    		retStr += "\t\t\tacceptProxyWithoutFQAN='"+acceptProxyWithoutFQAN+"'\n"; 
309     	if (!voGroup.equals(""))
310         	retStr += "\t\t\tvoGroup='"+voGroup+"'\n";
311     	if (!role.equals(""))
312     		retStr += "\t\t\trole='"+role+"'\n";
313     	if (retStr.charAt(retStr.length()-1)=='\n')
314     		retStr = retStr.substring(0, retStr.length()-1);
315     	retStr += "/>\n\n";
316     	return retStr;
317     }
318 
319     public void updateMembers() {
320    		getVoDB().loadUpdatedList(retrieveMembers());
321     }
322     
323     private UserGroupDB getVoDB() {
324     	return getVoObject().getDB( getName() );
325     }
326     
327     private VomsServer getVoObject() {
328     	if (getConfiguration()==null)
329     		throw new RuntimeException("Configuration has not yet been set for this class");    	
330     	return getConfiguration().getVomsServer(vomsServer);
331     }
332 
333     private void prepareFQAN() {
334         if (!voGroup.equals("")) {
335             if (!role.equals("") && !voGroup.equals(""))
336             	fqan = voGroup + "/Role=" + role;
337             else if (!voGroup.equals(""))
338                 fqan = voGroup;
339             else
340             	fqan = null;
341         }
342     }
343     
344     private List retrieveMembers() {
345         Properties p = System.getProperties();
346         try {
347             setProperties();
348             log.debug("SSL properties read: " + 
349             "sslCertfile='" + System.getProperty("sslCertfile") +
350             "' sslKey='" + System.getProperty("sslKey") +
351             "' sslKeyPasswd set:" + (System.getProperty("sslKeyPasswd")!=null) +
352             " sslCAFiles='" + System.getProperty("sslCAFiles") + "'" ); 
353             System.setProperty("axis.socketSecureFactory", "org.edg.security.trustmanager.axis.AXISSocketFactory");
354             VOMSAdmin voms = getVOMSAdmin();
355         	org.edg.security.voms.service.User[] users = null;
356             if (role.equals("")) {
357                 users = voms.listMembers( !getVoGroup().equals("")?getVoGroup():null );
358             } else if(!getVoGroup().equals("")) {
359                 users = voms.listUsersWithRole( getVoGroup(), "Role=" + getRole());
360             }        	
361             if (users.length > 0) {
362                 log.trace("Retrieved " + users.length + " users. First is: '" + users[0].getDN());
363             } else {
364                 log.trace("Retrieved no users.");
365             }
366             System.setProperties(p);
367             List entries = new ArrayList();
368             for (int n=0; n< users.length; n++) {
369             	GridUser gridUser = new GridUser(users[n].getDN(), fqan);
370                 entries.add(gridUser);
371             }
372             return entries;
373         } catch (Throwable e) {
374             log.error("Couldn't retrieve VOMS users: ", e);
375             System.out.println(e);
376             throw new RuntimeException("Couldn't retrieve users from VOMS server: " + e.getMessage(), e);
377         }
378     }
379     
380     private void setProperties() {
381     	VomsServer voObject = getVoObject();
382         log.debug( "SSL properties set: sslCertfile='" + voObject.getSslCertfile() + "' sslKey='" + voObject.getSslKey() + "' sslKeyPasswd set:" + (!voObject.getSslKeyPasswd().equals("")) + " sslCAFiles='" + voObject.getSslCAFiles() + "'" ); 
383         if (!voObject.getSslCertfile().equals("")) {
384             System.setProperty("sslCertfile", voObject.getSslCertfile());
385         }
386         if (!voObject.getSslKey().equals("")) {
387             System.setProperty("sslKey", voObject.getSslKey());
388         }
389         if (!voObject.getSslKeyPasswd().equals("")) {
390             System.setProperty("sslKeyPasswd", voObject.getSslKeyPasswd());
391         }
392         if (!voObject.getSslCAFiles().equals("")) {
393             System.setProperty("sslCAFiles", voObject.getSslCAFiles());
394         }
395     }
396 }