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.util.StringUtil;
13  
14  import java.net.URL;
15  import java.util.*;
16  
17  import javax.persistence.Entity;
18  import javax.persistence.Transient;
19  
20  import org.apache.log4j.Logger; 
21  
22  import org.glite.security.voms.*;
23  
24  
25  /** A group of users residing on a VOMS vo database. This class is able to 
26   * import a list of users from a VOMS server. It will store to a local
27   * medium through the UserGroupDB interface. It also manages the caching from
28   * the local database.
29   * <p>
30   * The authentication is done through the proxy, or a certificate/key/password
31   * combination. The parameters are to be set externally as system properties.
32   * The proxy can be set through "gridProxyFile" property. Other properties
33   * are "sslCertfile", "sslKey", "sslKeyPasswd" and "sslCAFiles". More documentation
34   * can be found in the documentation of the edg trustmanager  
35   *
36   * @author Gabriele Carcassi, Jay Packard
37   */
38  @Entity
39  public class VOMSUserGroup extends UserGroup {
40  	static protected final boolean defaultAcceptProxyWithoutFQAN = true;
41  	static protected String[] matchFQANTypes = {"ignore", "exact", "vorole", "role", "vogroup", "vo"};
42  	static protected final int defaultMatchFQANIndex = 0;
43  	protected String matchFQAN = matchFQANTypes[defaultMatchFQANIndex];
44  	static private Logger log = Logger.getLogger(VOMSUserGroup.class);
45  
46      static public Set<String> getMatchFQANTypes() {
47  		Set<String> retList = new TreeSet<String>();
48  		for(int i=0; i<matchFQANTypes.length; i++)
49  			retList.add(matchFQANTypes[i]);
50  		return retList;
51  	}
52      
53      // persistent variables
54      protected boolean acceptProxyWithoutFQAN = defaultAcceptProxyWithoutFQAN;
55      protected String fqan = null;
56      protected String role;
57      protected String voGroup;
58      protected String vomsServerUrls;
59      
60      static {
61      	System.setProperty("axis.socketSecureFactory", "org.glite.security.trustmanager.axis.AXISSocketFactory");
62      }
63      
64      public VOMSUserGroup() {
65      	super();
66      	hasCache = true;
67      }  
68  
69  	public VOMSUserGroup(Configuration configuration, String name) {
70  		super(configuration, name);
71      	hasCache = true;
72  	}
73  	
74      /**
75       * The scheme according to which the FQAN will be matched.
76       * <p>
77       * Possible values are:
78       * <ul>
79       *   <li>exact (default) - role, group, and vo have to match. </li>
80       *   <li>vorole - role and vo have to match.</li>
81       *   <li>role - rolehas to match.</li>
82       *   <li>group, vogroup - group and vo have to match.</li>
83       *   <li>vo - vo has to match.</li>
84       *   <li>ignore - no matching.</li>
85       * </ul>
86       * @return matching type as String.
87       */
88      public String getMatchFQAN() {
89     		return matchFQAN;
90      }
91      
92      /**
93       * Changes the role.
94       * @return The role name in the VOMS server (i.e. myrole), or "" for no role
95       */
96      public String getRole() {
97          return this.role;
98      }
99      
100     /**
101      * Returns the VO group.
102      * @return The group in the VOMS (i.e. /atlas/usatlas)
103      */
104     public String getVoGroup() {
105         return this.voGroup;
106     }
107 
108     public String getVomsServerUrls() {
109     	return vomsServerUrls;
110 	}
111 
112     /**
113      * True if non-VOMS will be accepted. If true, all non-VOMS proxies with a matchin
114      * DN will be matched. VOMS proxies won't be affected by the use of this property.
115      * @return True if group will accept non-VOMS proxies
116      */
117     public boolean isAcceptProxyWithoutFQAN() {
118         return this.acceptProxyWithoutFQAN;
119     }
120     
121     /**
122      * Convenience function for "ignore".equals(getmatchFQAN())
123      * @return False if FQAN is used during the match
124      */
125    public boolean isIgnoreFQAN() {
126         return matchFQAN.equals(matchFQANTypes[0]);
127     }
128 
129     public boolean isMember(GridUser gridUser) {
130     	if (gridUser.getFqanObj() == null) {
131             // If the user comes in without FQAN and we don't accept proxies without fqan,
132             // kick him out right away
133 	        if (!isAcceptProxyWithoutFQAN())
134 	            return false;
135 	        
136 	        // If the user comes in without FQAN and we accept proxies without it,
137 	        // we simply check whether the DN is in the database
138 	        else
139         		return isMember(new GridUser(gridUser.getDn(), fqan));
140     	}
141 
142         // We now know we don't have user.getFqanObj()==null
143 
144         // If we have vorole match, entire fqan has to be the same
145         if ("exact".equals(getMatchFQAN())) {
146             if (!gridUser.getFqan().equals(fqan))
147                 return false;
148         }
149         
150         // If we have a vo-role match, vo and role has to be the same
151         if ("vorole".equals(getMatchFQAN()) && gridUser.getFqanObj().getVo()!=null && gridUser.getFqanObj().getRole()!=null) {
152         	FQAN theFQAN = new FQAN(fqan);
153             if (!gridUser.getFqanObj().getVo().equals(theFQAN.getVo()) && !gridUser.getFqanObj().getRole().equals(theFQAN.getRole()))
154                 return false;
155         }
156         
157         // If we have a role match, role has to be the same
158         if ("role".equals(getMatchFQAN()) && gridUser.getFqanObj().getRole()!=null) {
159         	FQAN theFQAN = new FQAN(fqan);
160             if (!gridUser.getFqanObj().getRole().equals(theFQAN.getRole()))
161                 return false;
162         }
163         
164         // If we match the group, we make sure the VO starts with the group
165         if ("group".equals(getMatchFQAN()) || "vogroup".equals(getMatchFQAN())) {
166             if (!gridUser.getFqanObj().toString().startsWith(voGroup))
167                 return false;
168         }
169 
170         // If we match the vo, we check the vo is the same
171         if ("vo".equals(getMatchFQAN()) && gridUser.getFqanObj().getVo()!=null) {
172             FQAN theFQAN = new FQAN(fqan);
173             if (!gridUser.getFqanObj().getVo().equals(theFQAN.getVo()))
174                 return false;
175         }
176         
177         // FQAN matches, let's look up if the DN is in the db
178         // If not, he's kicked out
179         return super.isMember(new GridUser(gridUser.getDn(), fqan));
180     }
181     
182     /**
183      * Changes the way non-VOMS proxies are handled.
184      * @param acceptProxyWithoutFQAN True if group will accept non-VOMS proxies
185      */
186     @ConfigFieldAnnotation(label="Accept non-VOMS certificates")
187     public void setAcceptProxyWithoutFQAN(boolean acceptProxyWithoutFQAN) {
188         this.acceptProxyWithoutFQAN = acceptProxyWithoutFQAN;
189     }
190 
191     @Transient
192     public void setIgnoreFQAN(boolean ignoreFQAN) {
193     	matchFQAN = matchFQANTypes[0];
194     }
195     
196     /**
197      * Changes the scheme according to which the FQAN will be matched. See
198      * getMatchFQAN for more details.
199      * @param matchFQAN One of the following:  "exact, "vorole, "role", "vogroup", "vo", "ignore". (also "group" for backwards compat.)
200      */
201     @ConfigFieldAnnotation(label="Match VOMS certificate's FQAN as", choices="ignore, exact, vorole, role, vogroup, vo")
202     public void setMatchFQAN(String matchFQAN) {
203     	for(int i=0; i<matchFQANTypes.length; i++) {
204 	    	if (matchFQAN.equals("group"))
205 	    		matchFQAN = "vogroup";
206 	    	if (matchFQAN.equals(""))
207 	    		matchFQAN = "exact";
208     		if ( matchFQANTypes[i].equalsIgnoreCase(matchFQAN) ) {
209     	    	this.matchFQAN = matchFQAN;
210     			return;
211     		}
212     	}
213 		throw new RuntimeException("Invalid match FQAN string: "+matchFQAN);
214     }
215     
216     /**
217      * Changes the role.
218      * @param role The role in the VOMS (i.e.production)
219      */
220     @ConfigFieldAnnotation(label="Role", order=7) 
221     public void setRole(String role) {
222         this.role = role;
223         prepareFQAN();
224     }
225     
226 	/**
227      * Changes the VO group.
228      * @param voGroup The group in the VOMS (i.e. /atlas/usatlas)
229      */
230     @ConfigFieldAnnotation(label="VO/Group", example="/atlas/usatlas", help="optional", order=6) 
231     public void setVoGroup(String voGroup) {
232         this.voGroup = voGroup;
233         prepareFQAN();
234     }
235     
236     @ConfigFieldAnnotation(label="VOMS Server URLs", size=64, example="https://lcg-voms.cern.ch:8443/voms/atlas/services/VOMSAdmin", order=5) 
237 	public void setVomsServerUrls(String vomsServerUrls) {
238     	this.vomsServerUrls = vomsServerUrls;
239 	}
240 
241 	protected void prepareFQAN() {
242         if (role != null && voGroup != null)
243         	fqan = voGroup + "/Role=" + role;
244         else if (voGroup != null)
245             fqan = voGroup;
246         else
247         	fqan = null;
248     }
249 	
250 	protected Set<GridUser> retrieveMembers() {
251     	if (getConfiguration()==null)
252     		throw new RuntimeException("Configuration has not yet been set for this class");
253     	
254     	Set<GridUser> entries = new HashSet<GridUser>();
255     	Iterator<String> it = StringUtil.toList(vomsServerUrls).iterator();
256     	while (it.hasNext()) {
257     		String vomsServerUrl = it.next();
258 	        try {
259 	            VOMSAdminServiceLocator locator = new VOMSAdminServiceLocator();
260 	            log.info("Connecting to VOMS admin at " + vomsServerUrl);
261 	            VOMSAdmin voms = locator.getVOMSAdmin(new URL( vomsServerUrl ));
262 	        	org.glite.security.voms.User[] users = null;
263 	            if (role == null) {
264 	                users = voms.listMembers( getVoGroup() );
265 	            } else if(voGroup != null) {
266 	                users = voms.listUsersWithRole( getVoGroup(), "Role=" + getRole());
267 	            }
268 	            if (users.length > 0) {
269 	                log.info("Retrieved " + users.length + " users. First is: '" + users[0].getDN() + "'");
270 	            } else {
271 	                log.info("Retrieved no users.");
272 	            }
273 	            for (int n=0; n < users.length; n++) {
274 	            	GridUser gridUser = new GridUser(users[n].getDN(), fqan, users[n].getMail());
275 	                entries.add(gridUser);
276 	            }
277 	            break;
278 	        } catch (Throwable e) {
279 	        	String message = "Couldn't retrieve users: ";
280 	        	if (!it.hasNext()) {
281 	        		log.error(message, e);
282 		            throw new RuntimeException(message + e.getMessage());
283 	        	}
284 	        	else {
285 	        		log.warn(message, e);
286 	        	}
287 	        }
288     	}
289     	return entries;
290     }
291 }