001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005:
006: package com.sun.portal.search.db;
007:
008: import com.sun.portal.search.soif.*;
009: import com.sun.portal.search.rdm.*;
010: import com.sun.portal.search.util.SearchConfig;
011:
012: import java.util.*;
013:
014: /**
015: * This is the Security Management System built in Search.
016: * It consists two main function Authentication and Authorization.
017: * Authentication:
018: * A single plugable module implementing RDMAuthenticationModule interface is defined in search.conf
019: * Authorization:
020: * Multiple plugable modules implementing DatabaseSecurityModule interface are defined in search.conf
021: * There are three levels of authorization: database level, search and retrieve.
022: *
023: * Workflow:
024: * When a request made, Authentication module will be generating SToken with module's native authenticanion token in SToken.
025: * (For example, ssoToken for Portal)
026: *
027: * 1. If the request is for a database operation, a security module associated with the target database
028: * will be calling its CheckDatabasePermission function to grant/deny the access.
029: * 2. If it's a search request, it will use the module's getUserRoles function to obtain a set of roles for a filtered search on ReadACL
030: * 3. A retrieve filter will only apply if the request is not search.
031: * It used the user's roles obtained from security module to against rd's ReadACL.
032: */
033: public class RDMSecurityManager {
034:
035: public static String DB_PERMISSION_READ = "read";
036: public static String DB_PERMISSION_WRITE = "write";
037: public static final String RDM_AUTHENTICATION_MODULES = "rdm-authentication-module";
038: public static final String DATABASE_SECURITY_MODULES = "database-security-modules";
039: // static constants for database level security settings
040: static public final String DB_SECURITY_MODULE_ATTRNAME = "SecurityModule";
041: static public final String SECURITY_MODULE_DEFAULT = "default";
042: Map securityModuleMap = new HashMap();
043: protected List securityModuleList = new ArrayList();
044: private RDMAuthenticationModule authModule = null;
045: private String defaultSecurityModuleName = null;
046: private boolean usedInAdminCli = false;
047: private int maximumRoleSaecrh = -1;
048:
049: public RDMSecurityManager() {
050: //obtain an auth module
051: String authName = SearchConfig
052: .getValue(RDM_AUTHENTICATION_MODULES);
053: if (authName == null) {
054: authName = SearchConfig.getValue(SearchConfig.SECMGR); //backward compatible "security-manager";
055: }
056: if (authName != null) {
057: try {
058: Object o = Class.forName(authName).newInstance();
059: if (o instanceof RDMAuthenticationModule) {
060: authModule = (RDMAuthenticationModule) o;
061: }
062: } catch (Exception ce) {
063: }
064:
065: }
066: //obtain database security module
067: String ms = SearchConfig.getValue(DATABASE_SECURITY_MODULES);
068: if (ms != null) {
069: String[] mcs = ms.split(",");
070: for (int i = 0; i < mcs.length; i++) {
071: try {
072: DatabaseSecurityModule module = (DatabaseSecurityModule) Class
073: .forName(mcs[i]).newInstance();
074: this .addSecurityModule(module);
075: } catch (Exception e) {
076:
077: }
078: }
079: }
080: //obtain any database security module associated with auth module
081: if (authModule != null) {
082: DatabaseSecurityModule[] modules = authModule
083: .getAssociatedSecurityModules();
084: if (modules != null) {
085: for (int i = 0; i < modules.length; i++) {
086: this .addSecurityModule(modules[i]);
087: }
088: }
089: defaultSecurityModuleName = authModule
090: .getDefaultDatabaseSecurityModuleName();
091:
092: }
093: try {
094: int v = Integer.parseInt(SearchConfig
095: .getValue(SearchConfig.SEC_MAX_ROLESEARCH));
096: if (v > 0) {
097: this .maximumRoleSaecrh = v;
098: }
099: } catch (Exception e) {
100: //might not be defined in search.conf
101: }
102:
103: }
104:
105: public RDMSecurityManager(boolean forCli) {
106: DatabaseSecurityModule adminModule = new AdminSecurityModule();
107: addSecurityModule(adminModule);
108: this .defaultSecurityModuleName = adminModule.getName();
109: this .usedInAdminCli = forCli;
110: }
111:
112: public void addSecurityModule(DatabaseSecurityModule module) {
113: securityModuleList.add(module);
114: securityModuleMap.put(module.getName(), module);
115: }
116:
117: static RDMSecurityManager manager = new RDMSecurityManager(); // singelton
118:
119: /** Get a current RDM Security Manager
120: */
121: public static RDMSecurityManager getInstance() {
122: return manager;
123: }
124:
125: /** Set the RDM Security Manager for the first time
126: * @param manager the new RDM Security Manager
127: */
128: public synchronized static void setInstance(
129: RDMSecurityManager new_manager) {
130: manager = new_manager;
131: }
132:
133: /** Setup the RDMRequest Security Token
134: * Security infomation in req proceed request
135: * @param request the HttpServletRequest Object for checking cookies
136: * @param req the RDMRequest Object
137: */
138: public boolean initRDMSToken(Object request, RDMRequest req)
139: throws Exception {
140: if (authModule != null) {
141: authModule.initRDMSToken(request, req);
142: }
143: SToken st = req.getSToken();
144: if (st == null) {
145: st = new SToken(null, true, true, true);
146: }
147: RDMQuery query = req.getQuery();
148: if (query != null) {
149: st.setDatabaseName(query.getDatabase());
150: } else { // rd submit
151: st.setDatabaseName(req.getHeader().getSOIF().getValue(
152: RDM.SUBMIT_DB));
153: }
154: req.setSToken(st);
155: return true;
156: }
157:
158: public boolean xinitRDMSToken(RDMRequest req) throws Exception {
159:
160: SToken st = req.getSToken();
161: if (st == null) {
162: if (authModule != null) {
163: authModule.initRDMSToken(null, req);
164: }
165: }
166: st = req.getSToken();
167: if (st == null) {
168: st = new SToken(null, true, true, true);
169: }
170:
171: RDMQuery query = req.getQuery();
172: if (query != null) {
173: st.setDatabaseName(query.getDatabase());
174: } else { // rd submit
175: st.setDatabaseName(req.getHeader().getSOIF().getValue(
176: RDM.SUBMIT_DB));
177: }
178: req.setSToken(st);
179: return true; // SToken in req still null
180: }
181:
182: public String toString() {
183: return "Default -RDMSecMgr";
184: }
185:
186: /*public boolean checkSecurity() {
187: return false;
188: }*/
189:
190: /**
191: * Check the soif against the security token to access rights
192: *
193: * @param st
194: * @param soif the soif need to be filtered with respect to the stoken
195: * @throws java.lang.Exception
196: * @return
197: */
198: public SOIF filter(SToken st, SOIF soif) throws Exception {
199: if (!st.isCheckRDFilter()) {
200: return soif;
201: }
202: if (soif == null || !st.validateVirtualDBTag(soif)) {
203: return null;
204: }
205: DatabaseSecurityModule module = findSecurityModule(st);
206: if (module != null) {
207: Set roles = module.getUserRoles(st);
208: if (roles == null) {
209: return soif;
210: }
211: int i = 0;
212: boolean result = true;
213:
214: String acl;
215: for (i = 0;; i++) {
216: if (soif == null) {
217: result = false;
218: break;
219: }
220: acl = soif.getValue("readacl", i);
221: if (acl == null)
222: break;
223: result = false; // acl is non-empty
224:
225: if (roles.contains(acl)) {
226: result = true;
227: break;
228: }
229: }
230: return result ? soif : null;
231: }
232: return null;
233: }
234:
235: /**
236: * Check the soif against the security token to access rights
237: *
238: * @param st
239: * @param query the soif need to be qualified with respect to the stoken
240: * @throws java.lang.Exception
241: * @return
242: */
243: public String qualify_Nova_Query(SToken st, String query)
244: throws Exception {
245: query = st.appendVirtualDBQuery(query);
246: if (!st.isCheckSearch()) {
247: return query;
248: }
249: st.setCheckRDFilter(false);
250: String aclQuery = null;
251: query = st.appendVirtualDBQuery(query);
252: DatabaseSecurityModule module = findSecurityModule(st);
253: if (module != null) {
254: Set roles = module.getUserRoles(st);
255: if (roles == null) {
256: return query;
257: }
258: aclQuery = this .roleSet2Query(roles, maximumRoleSaecrh);
259: }
260: if (aclQuery != null) {
261: return "(" + query + ") <AND> (" + aclQuery + ")";
262: }
263: return query;
264:
265: }
266:
267: /**
268: * Finding a database security module
269: * @param st A Search Token for the request
270: * @throws java.lang.Exception
271: * @return A database security module for current request.
272: */
273: public DatabaseSecurityModule findSecurityModule(SToken st)
274: throws Exception {
275:
276: // get physical database name out
277:
278: String physicalDBName = st.getPhysicalDBName();
279: if (physicalDBName == null) {
280: return null;
281: }
282:
283: // get the dbsoif entry for the database.
284: SOIF dbsoif = DbManager.getRootDbEntry(st, physicalDBName);
285: if (dbsoif == null) {
286: return null;
287: }
288:
289: //
290: // Find out what is the database level security set to in
291: // the soif
292: //
293: String securityModuleName = dbsoif
294: .getValue(DB_SECURITY_MODULE_ATTRNAME);
295: if (securityModuleName == null) {
296: securityModuleName = defaultSecurityModuleName;
297: }
298:
299: if (securityModuleName == null) {
300: securityModuleName = SECURITY_MODULE_DEFAULT;
301: }
302: return (DatabaseSecurityModule) securityModuleMap
303: .get(securityModuleName);
304: }
305:
306: /**
307: * This method is called to find out if the current user
308: * has the authorization to perform database actions like
309: * search, fetch etc.
310: * @param st
311: * @param permissionName
312: * @param rd
313: * @throws com.sun.portal.search.rdm.RDMException
314: * @return
315: */
316: public boolean checkDatabasePermission(SToken st,
317: String permissionName, SOIF rd) throws RDMException {
318: if (!st.isCheckDatabaseAccess()) {
319: return true;
320: }
321: try {
322: DatabaseSecurityModule module = findSecurityModule(st);
323: if (module != null) {
324: boolean r = module.checkDatabasePermission(st,
325: permissionName, rd);
326: if (r) {
327: st.setCheckDatabaseAccess(false);
328: }
329: return r;
330: }
331: } catch (Exception e) {
332: throw new RDMException(
333: "Error on checking permission for database:"
334: + st.getPhysicalDBName() + "Exception:" + e);
335: }
336: throw new RDMException(
337: "Unable to get a security module for database:"
338: + st.getPhysicalDBName());
339: }
340:
341: /**
342: * Comvert a set of roles into a query
343: * @param set User's roles
344: * @return A query string.
345: */
346: public static String roleSet2Query(Set set, int max) {
347: String query = "";
348:
349: if (set == null) {
350: return query;
351: }
352: if (set.size() == 0) {
353: query = "(ReadACL = \"\")";
354: } else {
355: Iterator i = set.iterator();
356: while (i.hasNext() && max != 0) {
357: query += "(ReadACL = \""
358: + i.next().toString().toLowerCase() + "\")";
359: max--;
360: if (max != 0 && i.hasNext()) {
361: query += " <OR> ";
362: }
363: }
364: query += " <OR> (ReadACL = \"\")";
365: }
366: return query;
367: }
368:
369: /**
370: * A requested database will be created automatically if it does not exist.
371: * Before the db soif created in root db, this call back function will allow a security module to add attributes
372: * @param dbsoif A soif brfore adding to root db entry.
373: */
374: public void preDbSoifCreateCallback(SOIF dbsoif) {
375: for (int i = 0; i < this .securityModuleList.size(); i++) {
376: DatabaseSecurityModule module = (DatabaseSecurityModule) securityModuleList
377: .get(i);
378: if (module.onCreateCallback(dbsoif)) {
379: return;
380: }
381: }
382: }
383:
384: //
385: // Check if the current user is super user kinds
386: //
387: public boolean isPrivilegedUser(SToken stoken) throws Exception {
388: if (authModule != null) {
389: return authModule.isPrivilegedUser(stoken);
390: }
391: return false;
392: }
393:
394: class AdminSecurityModule implements DatabaseSecurityModule {
395: /**
396: * Getting the roles defined by this security module
397: *
398: * @param st SToken
399: * @return user's roles
400: * null - when the user has administrator privilige.
401: */
402: public Set getUserRoles(SToken st) throws Exception {
403: return null;
404: }
405:
406: /**
407: * Used for modifing the root db entry before it get put into root db
408: *
409: * @param dbsoif A root db entry
410: * @return true - if this module does apply.
411: */
412: public boolean onCreateCallback(SOIF dbsoif) {
413: return true;
414: }
415:
416: /**
417: * Checking the permission of an action on a given database
418: *
419: * @param st SToken
420: * @param permissionName The name of request action.
421: * @param rd A submit rd assoicated with this action.
422: * Security Module can add ReadACL if needed.
423: * @return true - if the action is allowed.
424: * @throws com.sun.portal.search.rdm.RDMException Exception
425: */
426: public boolean checkDatabasePermission(SToken st,
427: String permissionName, SOIF rd) throws RDMException {
428: return true;
429: }
430:
431: /**
432: * Name of this module.
433: * Search server uses this for assoicated with database.
434: *
435: * @return The name of this module
436: */
437: public String getName() {
438: return "Used4AdminCli";
439: }
440:
441: }
442:
443: }
|