001: //=============================================================================
002: //=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
003: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
004: //=== and United Nations Environment Programme (UNEP)
005: //===
006: //=== This program is free software; you can redistribute it and/or modify
007: //=== it under the terms of the GNU General Public License as published by
008: //=== the Free Software Foundation; either version 2 of the License, or (at
009: //=== your option) any later version.
010: //===
011: //=== This program is distributed in the hope that it will be useful, but
012: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
013: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: //=== General Public License for more details.
015: //===
016: //=== You should have received a copy of the GNU General Public License
017: //=== along with this program; if not, write to the Free Software
018: //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
019: //===
020: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
021: //=== Rome - Italy. email: geonetwork@osgeo.org
022: //==============================================================================
023:
024: package org.fao.geonet.kernel;
025:
026: import java.sql.SQLException;
027: import java.util.HashMap;
028: import java.util.HashSet;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.Set;
032: import java.util.StringTokenizer;
033: import jeeves.resources.dbms.Dbms;
034: import jeeves.server.ProfileManager;
035: import jeeves.server.UserSession;
036: import jeeves.server.context.ServiceContext;
037: import org.fao.geonet.GeonetContext;
038: import org.fao.geonet.constants.Geonet;
039: import org.fao.geonet.kernel.setting.SettingManager;
040: import org.jdom.Element;
041:
042: //=============================================================================
043:
044: /** Handles the access to a metadata depending on the metadata/group
045: */
046:
047: public class AccessManager {
048: public static final String OPER_VIEW = "0";
049: public static final String OPER_DOWNLOAD = "1";
050: public static final String OPER_NOTIFY = "3";
051: public static final String OPER_DYNAMIC = "5";
052: public static final String OPER_FEATURED = "6";
053:
054: //--------------------------------------------------------------------------
055: //---
056: //--- Constructor
057: //---
058: //--------------------------------------------------------------------------
059:
060: /** Loads all permissions from database and caches them
061: */
062:
063: public AccessManager(Dbms dbms, SettingManager sm)
064: throws SQLException {
065: settMan = sm;
066:
067: List operList = dbms.select("SELECT * FROM Operations")
068: .getChildren();
069:
070: for (Object o : operList) {
071: Element oper = (Element) o;
072:
073: String id = oper.getChildText("id");
074: String name = oper.getChildText("name");
075:
076: //--- build Hashtable of all operations
077: hsAllOps.add(id);
078:
079: hmIdToName.put(Integer.parseInt(id), name);
080: hmNameToId.put(name, Integer.parseInt(id));
081: }
082: }
083:
084: //--------------------------------------------------------------------------
085: //---
086: //--- API methods
087: //---
088: //--------------------------------------------------------------------------
089:
090: /** Given a user(session) a list of groups and a metadata returns all operations that user
091: * can perform on that metadata (an set of OPER_XXX as keys)
092: * If the user is authenticated the permissions are taken from the groups the user belong
093: * If the user is not authenticated, a dynamic group is assigned depending on user location
094: * (0 for internal and 1 for external)
095: *
096: */
097:
098: public HashSet<String> getOperations(ServiceContext context,
099: String mdId, String ip) throws Exception {
100: Dbms dbms = (Dbms) context.getResourceManager().open(
101: Geonet.Res.MAIN_DB);
102: UserSession usrSess = context.getUserSession();
103: String profile = usrSess.getProfile();
104:
105: // if user is an administrator just allow any operation
106: if (usrSess.isAuthenticated()
107: && profile.equals(Geonet.Profile.ADMINISTRATOR))
108: return hsAllOps;
109:
110: // build group list
111: Set<String> groups = getUserGroups(dbms, usrSess, ip);
112: StringBuffer groupList = new StringBuffer();
113:
114: for (Iterator i = groups.iterator(); i.hasNext();) {
115: String groupId = (String) i.next();
116: groupList.append(groupId);
117:
118: if (i.hasNext())
119: groupList.append(", ");
120: }
121: // get allowed operations
122: StringBuffer query = new StringBuffer();
123:
124: query.append("SELECT DISTINCT operationId ");
125: query.append("FROM OperationAllowed ");
126: query.append("WHERE groupId IN (" + groupList.toString()
127: + ") ");
128: query.append("AND metadataId = " + mdId);
129:
130: Element operations = dbms.select(query.toString());
131:
132: // build result
133: HashSet<String> result = new HashSet<String>();
134:
135: ProfileManager pm = context.getProfileManager();
136: if (profile == null)
137: profile = ProfileManager.GUEST;
138:
139: for (Iterator iter = operations.getChildren().iterator(); iter
140: .hasNext();) {
141: Element record = (Element) iter.next();
142: String operId = record.getChildText("operationid");
143:
144: // no checking for OPER_NOTIFY, OPER_DYNAMIC and OPER_FEATURED
145: // if (operId.equals(OPER_VIEW) && !pm.hasAccessTo(profile, VIEW_SERVICE))
146: // continue;
147:
148: // if (operId.equals(OPER_DOWNLOAD))
149: // continue;
150:
151: result.add(operId);
152: }
153:
154: if (canEdit(context, mdId))
155: result.add(OPER_VIEW);
156:
157: return result;
158: }
159:
160: // --------------------------------------------------------------------------
161: /** Returns all groups accessible by the user (a set of ids)
162: */
163:
164: public Set<String> getUserGroups(Dbms dbms, UserSession usrSess,
165: String ip) throws Exception {
166: HashSet<String> hs = new HashSet<String>();
167:
168: // add All (1) network group
169: hs.add("1");
170:
171: if (ip != null && isIntranet(ip))
172: hs.add("0");
173:
174: // get other groups
175: if (usrSess.isAuthenticated()) {
176: if (usrSess.getProfile().equals(
177: Geonet.Profile.ADMINISTRATOR)) {
178: Element elUserGrp = dbms
179: .select("SELECT id FROM Groups");
180:
181: List list = elUserGrp.getChildren();
182:
183: for (int i = 0; i < list.size(); i++) {
184: Element el = (Element) list.get(i);
185: String groupId = el.getChildText("id");
186: hs.add(groupId);
187: }
188: } else {
189: Element elUserGrp = dbms
190: .select("SELECT groupId FROM UserGroups WHERE userId="
191: + usrSess.getUserId());
192:
193: List list = elUserGrp.getChildren();
194:
195: for (int i = 0; i < list.size(); i++) {
196: Element el = (Element) list.get(i);
197: String groupId = el.getChildText("groupid");
198: hs.add(groupId);
199: }
200: }
201: }
202: return hs;
203: }
204:
205: //--------------------------------------------------------------------------
206:
207: public Set<String> getVisibleGroups(Dbms dbms, int userId)
208: throws Exception {
209: HashSet<String> hs = new HashSet<String>();
210:
211: String query = "SELECT * FROM Users WHERE id=?";
212: List list = dbms.select(query, userId).getChildren();
213:
214: //--- return an empty list if the user does not exist
215:
216: if (list.size() == 0)
217: return hs;
218:
219: Element user = (Element) list.get(0);
220: String profile = user.getChildText("profile");
221:
222: query = profile.equals(Geonet.Profile.ADMINISTRATOR) ? "SELECT id AS grp FROM Groups"
223: : "SELECT groupId AS grp FROM UserGroups WHERE userId="
224: + userId;
225:
226: Element elUserGrp = dbms.select(query);
227:
228: for (Object o : elUserGrp.getChildren()) {
229: Element el = (Element) o;
230: String groupId = el.getChildText("grp");
231: hs.add(groupId);
232: }
233:
234: return hs;
235: }
236:
237: //--------------------------------------------------------------------------
238: /** Returns true if, and only if, at least one of these conditions is satisfied
239: * - The user is the metadata owner
240: * - The user is an Administrator
241: * - The user is a Reviewer and the metadata groupOwner is one of his groups
242: */
243:
244: public boolean canEdit(ServiceContext context, String id)
245: throws Exception {
246: UserSession us = context.getUserSession();
247:
248: if (!us.isAuthenticated())
249: return false;
250:
251: //--- retrieve metadata info
252:
253: GeonetContext gc = (GeonetContext) context
254: .getHandlerContext(Geonet.CONTEXT_NAME);
255: DataManager dm = gc.getDataManager();
256:
257: Dbms dbms = (Dbms) context.getResourceManager().open(
258: Geonet.Res.MAIN_DB);
259:
260: MdInfo info = dm.getMetadataInfo(dbms, id);
261:
262: //--- harvested metadata cannot be edited
263:
264: if (info == null || info.isHarvested)
265: return false;
266:
267: //--- check if the user is an administrator
268:
269: if (us.getProfile().equals(Geonet.Profile.ADMINISTRATOR))
270: return true;
271:
272: //--- check if the user is the metadata owner
273:
274: if (us.getUserId().equals(info.owner))
275: return true;
276:
277: //--- check if the user is a reviewer
278:
279: if (!us.getProfile().equals(Geonet.Profile.REVIEWER))
280: return false;
281:
282: //--- if there is no group owner then the reviewer cannot review
283:
284: if (info.groupOwner == null)
285: return false;
286:
287: for (String userGroup : getUserGroups(dbms, us, null))
288: if (userGroup.equals(info.groupOwner))
289: return true;
290:
291: return false;
292: }
293:
294: //--------------------------------------------------------------------------
295:
296: public int getPrivilegeId(String descr) {
297: return hmNameToId.containsKey(descr) ? hmNameToId.get(descr)
298: : -1;
299: }
300:
301: //--------------------------------------------------------------------------
302:
303: public String getPrivilegeName(int id) {
304: return hmIdToName.get(id);
305: }
306:
307: //--------------------------------------------------------------------------
308: //---
309: //--- Private methods
310: //---
311: //--------------------------------------------------------------------------
312:
313: private boolean isIntranet(String ip) {
314: //--- consider IPv4 & IPv6 loopback
315: //--- we use 'startsWith' because some addresses can be 0:0:0:0:0:0:0:1%0
316:
317: if (ip.startsWith("0:0:0:0:0:0:0:1") || ip.equals("127.0.0.1"))
318: return true;
319:
320: String network = settMan.getValue("system/intranet/network");
321: String netmask = settMan.getValue("system/intranet/netmask");
322:
323: long lIntranetNet = getAddress(network);
324: long lIntranetMask = getAddress(netmask);
325: long lAddress = getAddress(ip);
326:
327: return (lAddress & lIntranetMask) == lIntranetNet;
328: }
329:
330: //--------------------------------------------------------------------------
331:
332: /** Converts an ip x.x.x.x into a long
333: */
334:
335: private long getAddress(String ip) {
336: StringTokenizer st = new StringTokenizer(ip, ".");
337:
338: long a1 = Integer.parseInt(st.nextToken());
339: long a2 = Integer.parseInt(st.nextToken());
340: long a3 = Integer.parseInt(st.nextToken());
341: long a4 = Integer.parseInt(st.nextToken());
342:
343: return a1 << 24 | a2 << 16 | a3 << 8 | a4;
344: }
345:
346: //--------------------------------------------------------------------------
347: //---
348: //--- Variables
349: //---
350: //--------------------------------------------------------------------------
351:
352: private SettingManager settMan;
353: private HashSet<String> hsAllOps = new HashSet<String>();
354:
355: private HashMap<Integer, String> hmIdToName = new HashMap<Integer, String>();
356: private HashMap<String, Integer> hmNameToId = new HashMap<String, Integer>();
357: }
358:
359: //=============================================================================
|