KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensourcestrategies > crmsfa > security > CrmsfaSecurity


1 /*
2  * Copyright (c) 2006 - 2007 Open Source Strategies, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the Honest Public License.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * Honest Public License for more details.
11  *
12  * You should have received a copy of the Honest Public License
13  * along with this program; if not, write to Funambol,
14  * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA
15  */

16 /* Copyright (c) 2005-2006 Open Source Strategies, Inc. */
17
18 /*
19  * $Id:$
20  *
21  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
22  *
23  * Permission is hereby granted, free of charge, to any person obtaining a
24  * copy of this software and associated documentation files (the "Software"),
25  * to deal in the Software without restriction, including without limitation
26  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
27  * and/or sell copies of the Software, and to permit persons to whom the
28  * Software is furnished to do so, subject to the following conditions:
29  *
30  * The above copyright notice and this permission notice shall be included
31  * in all copies or substantial portions of the Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
34  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
38  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
39  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40  */

41 package com.opensourcestrategies.crmsfa.security;
42
43 import java.util.Map JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.sql.Timestamp JavaDoc;
47
48 import javolution.util.FastMap;
49
50 import org.ofbiz.base.util.Debug;
51 import org.ofbiz.base.util.UtilMisc;
52 import org.ofbiz.base.util.UtilDateTime;
53 import org.ofbiz.entity.GenericDelegator;
54 import org.ofbiz.entity.GenericEntityException;
55 import org.ofbiz.entity.GenericValue;
56 import org.ofbiz.entity.condition.EntityCondition;
57 import org.ofbiz.entity.condition.EntityConditionList;
58 import org.ofbiz.entity.condition.EntityExpr;
59 import org.ofbiz.entity.condition.EntityOperator;
60 import org.ofbiz.entity.util.EntityUtil;
61 import org.ofbiz.service.DispatchContext;
62 import org.ofbiz.service.GenericServiceException;
63 import org.ofbiz.service.LocalDispatcher;
64 import org.ofbiz.service.ServiceUtil;
65 import org.ofbiz.security.Security;
66
67 import com.opensourcestrategies.crmsfa.cases.UtilCase;
68 import com.opensourcestrategies.crmsfa.activities.UtilActivity;
69 import com.opensourcestrategies.crmsfa.opportunities.UtilOpportunity;
70 import com.opensourcestrategies.crmsfa.party.PartyHelper;
71
72 /**
73  * Special security methods for the CRM/SFA Application
74  *
75  * @author <a HREF="mailto:leon@opensourcestrategies.com">Leon Torres</a>
76  * @author <a HREF="mailto:sichen@opensourcestrategies.com">Si Chen</a>
77  * @version $Rev: 312 $
78  */

79
80 public class CrmsfaSecurity {
81
82     public static final String JavaDoc module = CrmsfaSecurity.class.getName();
83
84     /**
85      * This method supplements the standard OFBIZ security model with a security check specified in PartyRelationship.
86      * It first does the standard OFBIZ security checks, then sees if an unexpired PartyRelationship exists where partyIdFrom=partyIdFor,
87      * partyIdTo=UserLogin.partyId, and whose securityGroupId contains the security permission of module+"_MANAGER" or module+"_OPERATION".
88      * If not, it will check one more time on whether, for any partyIdFrom for which a security permission does exist, there exists
89      * a current (unexpired) PartyRelationship where partyIdFrom=partyIdFor, partyIdTo={partyId for which the required permission exists.}
90      * If any of these are true, then the permission is true. Otherwise, or if any entity operation errors occurred, false is returned.
91      *
92      * @param security - Security object
93      * @param securityModule - The module to check (e.g., "CRMSFA_ACCOUNT", "PARTYMGR")
94      * @param securityOperation - What operation is being checked (e.g., "_VIEW", "_CREATE", "_UPDATE")
95      * @param userLogin - The userLogin to check permission for
96      * @param partyIdForm - What Account or Party the userLogin has permission to perform the operation on
97      */

98     public static boolean hasPartyRelationSecurity(Security security, String JavaDoc securityModule, String JavaDoc securityOperation,
99             GenericValue userLogin, String JavaDoc partyIdFor) {
100
101         if ((userLogin == null) || (userLogin.getDelegator() == null)) {
102             Debug.logError("userLogin is null or has no associated delegator", module);
103             return false;
104         }
105                 
106         // check ${securityModule}_MANAGER permission
107
if (security.hasEntityPermission(securityModule, "_MANAGER", userLogin)) {
108             return true;
109         }
110         // check ${securityModule}_${securityOperation} permission
111
if (security.hasEntityPermission(securityModule, securityOperation, userLogin)) {
112             return true;
113         }
114         // TODO: #3 and #4 in http://jira.undersunconsulting.com/browse/OFBIZ-638
115

116         try {
117             // now we'll need to do some searching so we should get a delegator from user login
118
GenericDelegator delegator = userLogin.getDelegator();
119             
120             // validate that partyIdFor is in our system in a proper role
121
String JavaDoc roleTypeIdFor = PartyHelper.getFirstValidRoleTypeId(partyIdFor, PartyHelper.CLIENT_PARTY_ROLES, delegator);
122             if (roleTypeIdFor == null) {
123                 Debug.logError("Failed to check permission for partyId [" + partyIdFor
124                         + "] because that party does not have a valid role. I.e., it is not an Account, Contact, Lead, etc.", module);
125                 return false;
126             }
127
128             // Now get a list of all the parties for whom the userLogin's partyId has the required securityModule+"_MANAGER" or securityModule+securityOperation permission
129
// due to a grant by PartyRelationship.securityGroupId
130
EntityCondition filterByDateCondition = EntityUtil.getFilterByDateExpr();
131             EntityConditionList operationConditon = new EntityConditionList(
132                     UtilMisc.toList(new EntityExpr("permissionId", EntityOperator.EQUALS, securityModule+"_MANAGER"),
133                                     new EntityExpr("permissionId", EntityOperator.EQUALS, securityModule+securityOperation)),
134                     EntityOperator.OR);
135             EntityConditionList searchConditions = new EntityConditionList(
136                     UtilMisc.toList(new EntityExpr("partyIdTo", EntityOperator.EQUALS, userLogin.getString("partyId")),
137                                     operationConditon,
138                                     filterByDateCondition),
139                     EntityOperator.AND);
140             List JavaDoc permittedRelationships = delegator.findByCondition("PartyRelationshipAndPermission", searchConditions, null, null);
141             
142             // do any of these explicitly state a permission for partyIdFor? If so, then we're done
143
List JavaDoc directPermittedRelationships = EntityUtil.filterByAnd(permittedRelationships, UtilMisc.toMap("partyIdFrom", partyIdFor));
144             if ((directPermittedRelationships != null) && (directPermittedRelationships.size() > 0)) {
145                 if (Debug.verboseOn()) {
146                     Debug.logVerbose(userLogin + " has direct permitted relationship for " + partyIdFor, module);
147                 }
148                 return true;
149             }
150             
151             // if not, then there is one more thing to check: for all the permitted relationships, were there any which are in turn related
152
// to the partyIdFor through another current (non-expired) PartyRelationship? Note that here we had to break with convention because
153
// of the way PartyRelationship for CONTACT is written (ie, CONTACT_REL_INV is opposite of ASSIGNED_TO, etc. See comments in CRMSFADemoData.xml
154
for (Iterator JavaDoc pRi = permittedRelationships.iterator(); pRi.hasNext(); ) {
155                 GenericValue permittedRelationship = (GenericValue) pRi.next();
156                 EntityConditionList indirectConditions = new EntityConditionList(
157                         UtilMisc.toList(new EntityExpr("partyIdFrom", EntityOperator.EQUALS, partyIdFor),
158                                         new EntityExpr("partyIdTo", EntityOperator.EQUALS, permittedRelationship.getString("partyIdFrom")),
159                                         filterByDateCondition),
160                         EntityOperator.AND);
161                 List JavaDoc indirectPermittedRelationships = delegator.findByCondition("PartyRelationship", indirectConditions, null, null);
162                 if ((indirectPermittedRelationships != null) && (indirectPermittedRelationships.size() > 0)) {
163                     if (Debug.verboseOn()) {
164                         Debug.logVerbose(userLogin + " has indirect permitted relationship for " + partyIdFor, module);
165                     }
166                     return true;
167                 }
168             }
169     
170         } catch (GenericEntityException ex) {
171             Debug.logError("Unable to determine security from party relationship due to error " + ex.getMessage(), module);
172             return false;
173         }
174
175         Debug.logWarning("Checked UserLogin [" + userLogin + "] for permission to perform [" + securityModule + "] + [" + securityOperation + "] on partyId = [" + partyIdFor + "], but permission was denied", module);
176         return false;
177     }
178
179     /**
180      * Checks if a userLogin has permission to perform an operation on an opportunity.
181      * The userLogin must pass CRMSFA_OPP_${securityOperation} for all associated accounts and contacts.
182      */

183     public static boolean hasOpportunityPermission(Security security, String JavaDoc securityOperation, GenericValue userLogin, String JavaDoc salesOpportunityId) {
184
185         GenericDelegator delegator = userLogin.getDelegator();
186         try {
187             // check for existance first
188
GenericValue opportunity = delegator.findByPrimaryKeyCache("SalesOpportunity", UtilMisc.toMap("salesOpportunityId", salesOpportunityId));
189             if (opportunity == null) {
190                 return false;
191             }
192
193             // check for closed opportunities for actions that are not _VIEW
194
if (!"_VIEW".equals(securityOperation) && "SOSTG_CLOSED".equals(opportunity.getString("opportunityStageId"))) {
195                 return false;
196             }
197
198             // check that userLogin can perform this operation on all associated accounts (orthogonal to leads)
199
List JavaDoc accounts = UtilOpportunity.getOpportunityAccountPartyIds(delegator, salesOpportunityId);
200             for (Iterator JavaDoc iter = accounts.iterator(); iter.hasNext(); ) {
201                 if (!hasPartyRelationSecurity(security, "CRMSFA_OPP", securityOperation, userLogin, (String JavaDoc) iter.next())) {
202                     return false;
203                 }
204             }
205
206             // check that userLogin can perform this operation on all associated leads (orthogonal to accounts)
207
List JavaDoc leads = UtilOpportunity.getOpportunityLeadPartyIds(delegator, salesOpportunityId);
208             for (Iterator JavaDoc iter = leads.iterator(); iter.hasNext(); ) {
209                 if (!hasPartyRelationSecurity(security, "CRMSFA_OPP", securityOperation, userLogin, (String JavaDoc) iter.next())) {
210                     return false;
211                 }
212             }
213
214             // check that userLogin can perform this operation on all associated contacts
215
List JavaDoc contacts = UtilOpportunity.getOpportunityContactPartyIds(delegator, salesOpportunityId);
216             for (Iterator JavaDoc iter = contacts.iterator(); iter.hasNext(); ) {
217                 if (!hasPartyRelationSecurity(security, "CRMSFA_OPP", securityOperation, userLogin, (String JavaDoc) iter.next())) {
218                     return false;
219                 }
220             }
221         } catch (GenericEntityException e) {
222             Debug.logError(e, "Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_OPP] + [" + securityOperation + "] on salesOpportunityId = [" + salesOpportunityId + "], but permission was denied due to exception: " + e.getMessage(), module);
223             return false;
224         }
225
226         // everything was passed
227
return true;
228     }
229
230     /**
231      * Checks if a userLogin has permission to perform an operation on a case. Cases are associated with accounts and contacts.
232      * They also have someone in the role of request taker, but this person cannot do anything. Module CRMSFA_CASE is implied.
233      */

234     public static boolean hasCasePermission(Security security, String JavaDoc securityOperation, GenericValue userLogin, String JavaDoc custRequestId) {
235         GenericDelegator delegator = userLogin.getDelegator();
236         try {
237             // check for existance first
238
GenericValue custRequest = delegator.findByPrimaryKeyCache("CustRequest", UtilMisc.toMap("custRequestId", custRequestId));
239             if (custRequest == null) {
240                 return false;
241             }
242
243             // check for closed cases for actions that are not _VIEW
244
String JavaDoc statusId = custRequest.getString("statusId");
245             if (!"_VIEW".equals(securityOperation) && UtilCase.caseIsInactive(custRequest)) {
246                 return false;
247             }
248
249             // use the cases helper method to get the PartyRelationshipAndCaseRoles for accounts and contacts of this case
250
List JavaDoc roles = UtilCase.getCaseAccountsAndContacts(delegator, custRequestId);
251             for (Iterator JavaDoc iter = roles.iterator(); iter.hasNext(); ) {
252                 GenericValue role = (GenericValue) iter.next(); // we're interested in the partyIdFrom, which is also the partyId of PartyRelationshipAndCaseRole
253
if (hasPartyRelationSecurity(security, "CRMSFA_CASE", securityOperation, userLogin, role.getString("partyId"))) {
254                     return true;
255                 }
256             }
257         } catch (GenericEntityException e) {
258             Debug.logError(e, "Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_CASE] + [" + securityOperation + "] on custRequestId = [" + custRequestId + "], but permission was denied due to exception: " + e.getMessage(), module);
259         }
260         return false;
261     }
262
263     /**
264      * Checks if a userLogin has permission to perform an operation on a activity. Activities are workEfforts that have associations to accounts, contacts, leads,
265      * opportunities and cases using various map entities. The user will need to pass all security checks for each association. This is to prevent the user from
266      * doing things when he has access to only one assocation but not all.
267      *
268      * First, the user must pass a general CRMSFA_ACT_${securityOperation} check.
269      * Then, if the internalPartyId is supplied, the user must pass the appropriate CRMSFA_ACCOUNT/CONTACT/LEAD_${securityOperation} check.
270      * Then, if the salesOpportunityId is supplied, the user must pass CRMSFA_OPP_${securityOperation}
271      * Then, if the custRequestId is supplied, the user must pass CRMSFA_CASE_${securityOperation}
272      */

273     public static boolean hasActivityPermission(Security security, String JavaDoc securityOperation, GenericValue userLogin,
274             String JavaDoc workEffortId, String JavaDoc internalPartyId, String JavaDoc salesOpportunityId, String JavaDoc custRequestId) {
275
276         // first check general CRMSFA_ACT_${securityOperation} permission
277
if (!security.hasEntityPermission("CRMSFA_ACT", securityOperation, userLogin)) {
278             Debug.logWarning("Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_ACT] + [" + securityOperation + "] in general but permission was denied.", module);
279             return false;
280         }
281
282         GenericDelegator delegator = userLogin.getDelegator();
283         try {
284             // check for existance first
285
GenericValue workEffort = delegator.findByPrimaryKeyCache("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId));
286             if (workEffort == null) {
287                 return false;
288             }
289
290             // check for closed activities for actions that are not _VIEW
291
if (!"_VIEW".equals(securityOperation) && UtilActivity.activityIsInactive(workEffort)) {
292                 return false;
293             }
294
295             // if there is an internalPartyId, check to see if user has permission for a party
296
if ((internalPartyId != null) && !internalPartyId.equals("")) {
297
298                 // determine the security module
299
String JavaDoc securityModule = getSecurityModuleOfInternalParty(internalPartyId, delegator);
300                 if (securityModule == null) {
301                     Debug.logWarning("Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_ACT] + [" + securityOperation + "] on workEffortId = [" + workEffortId + "] but permission was denied because internalPartyId=[" + internalPartyId + "] has an unknown roleTypeId", module);
302                     return false;
303                 }
304  
305                 // see if user can do this operation on this party
306
if (!hasPartyRelationSecurity(security, securityModule, securityOperation, userLogin, internalPartyId)) {
307                     return false;
308                 }
309             }
310
311             // if there is an opportunity, check to see if user has OPP permission
312
if ((salesOpportunityId != null) && !salesOpportunityId.equals("")) {
313                 if (!hasOpportunityPermission(security, securityOperation, userLogin, salesOpportunityId)) {
314                     return false;
315                 }
316             }
317
318             // if there is a case, check to see if user has CASE permission
319
if ((custRequestId != null) && !custRequestId.equals("")) {
320                 if (!hasCasePermission(security, securityOperation, userLogin, custRequestId)) {
321                     return false;
322                 }
323             }
324         } catch (GenericEntityException e) {
325             Debug.logError(e, "Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_ACT] + [" + securityOperation + "] on workEffortId = [" + workEffortId + "], internalPartyId=[" + internalPartyId + "], salesOpportunityId=[" + salesOpportunityId + "], custRequestId = [" + custRequestId + "], but permission was denied due to an exception: " + e.getMessage(), module);
326             return false;
327         }
328
329         // the user has passed everything
330
return true;
331     }
332
333     /**
334      * As above, but checks permission for every single existing association for a work effort. As a short cut, this will only check for parties which are directly
335      * associated with the work effort through WorkEffortPartyAssociations. If the application changes to allow the existance of work efforts without any
336      * party associations, then this method must be changed to relfect that. TODO: comprehensive (check case and opp security)
337      */

338     public static boolean hasActivityPermission(Security security, String JavaDoc securityOperation, GenericValue userLogin, String JavaDoc workEffortId) {
339         // first check general CRMSFA_ACT_${securityOperation} permission
340
if (!security.hasEntityPermission("CRMSFA_ACT", securityOperation, userLogin)) {
341             Debug.logWarning("Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_ACT] + [" + securityOperation + "] in general but permission was denied.", module);
342             return false;
343         }
344
345         GenericDelegator delegator = userLogin.getDelegator();
346         try {
347             // check for existance first
348
GenericValue workEffort = delegator.findByPrimaryKeyCache("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId));
349             if (workEffort == null) {
350                 return false;
351             }
352
353             // check for closed activities for actions that are not _VIEW
354
if (!"_VIEW".equals(securityOperation) && UtilActivity.activityIsInactive(workEffort)) {
355                 return false;
356             }
357
358             List JavaDoc parties = UtilActivity.getActivityParties(delegator, workEffortId);
359             for (Iterator JavaDoc iter = parties.iterator(); iter.hasNext(); ) {
360                 String JavaDoc internalPartyId = ((GenericValue) iter.next()).getString("partyId");
361                 String JavaDoc securityModule = getSecurityModuleOfInternalParty(internalPartyId, delegator);
362                 if (!hasPartyRelationSecurity(security, securityModule, securityOperation, userLogin, internalPartyId)) {
363                     return false;
364                 }
365             }
366         } catch (GenericEntityException e) {
367             Debug.logError(e, "Checked UserLogin [" + userLogin + "] for permission to perform [CRMSFA_ACT] + [" + securityOperation + "] on all associations with workEffortId=[" + workEffortId + "] but permission was denied due to an exception: " + e.getMessage(), module);
368             return false;
369         }
370
371         // the user has passed everything
372
return true;
373
374     }
375
376     /**
377      * Get the security module relevant to the role of the given internal partyId.
378      * @return The module as a string, such as "CRMSFA_ACCOUNT" for ACCOUNT partyIds or null if the role type is not found
379      */

380     public static String JavaDoc getSecurityModuleOfInternalParty(String JavaDoc partyId, GenericDelegator delegator) throws GenericEntityException {
381         String JavaDoc roleTypeId = PartyHelper.getFirstValidInternalPartyRoleTypeId(partyId, delegator);
382         if ("ACCOUNT".equals(roleTypeId)) return "CRMSFA_ACCOUNT";
383         if ("CONTACT".equals(roleTypeId)) return "CRMSFA_CONTACT";
384         if ("PROSPECT".equals(roleTypeId)) return "CRMSFA_LEAD";
385         return null;
386     }
387 }
388
Popular Tags