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