/force-app/main/default/classes/SFDCAccessController.cls

https://github.com/ForceDotComLabs/survey-force · Visual Basic for Applications · 401 lines · 355 code · 46 blank · 0 comment · 56 complexity · 720bc425c5157a4dd4ac3c9078fba25b MD5 · raw file

  1. /**
  2. * OWASP Enterprise Security API (ESAPI)
  3. *
  4. * This file is part of the Open Web Application Security Project (OWASP)
  5. * Enterprise Security API (ESAPI) project. For details, please see
  6. * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  7. *
  8. * Copyright (c) 2010 - Salesforce.com
  9. *
  10. * The Apex ESAPI implementation is published by Salesforce.com under the New BSD license. You should read and accept the
  11. * LICENSE before you use, modify, and/or redistribute this software.
  12. *
  13. * @author Yoel Gluck (securecloud .at. salesforce.com) <a href="http://www.salesforce.com">Salesforce.com</a>
  14. * @created 2010
  15. */
  16. /**
  17. * This class provides access control functionality to enforce CRUD/FLS and sharing in the force.com platform.
  18. */
  19. public with sharing class SFDCAccessController {
  20. /**
  21. * OperationMode - this enum defines the DB operations mode to be used.
  22. * <br>
  23. * You can set the operation mode in the constructor or later using the setOperatoinMode() method.
  24. * If you use the default constructor, we will set it to ALL_OR_NONE.
  25. */
  26. public enum OperationMode {
  27. /**
  28. * Will make sure all required fields have the proper permissions before any operation takes place.
  29. */
  30. ALL_OR_NONE,
  31. /**
  32. * Will only set fields that are allowed. Other fields will be omitted from operation, but operation will continue.
  33. */
  34. BEST_EFFORT
  35. }
  36. public OperationMode omode {get;set;} // the current operation mode of this instance.
  37. public SFDCAccessController() {
  38. omode = OperationMode.ALL_OR_NONE; // defaults to all or none
  39. }
  40. // Shortcut function
  41. public Map<String,Schema.SObjectField> getFieldMap(SObjectType someType){
  42. return someType.getDescribe().fields.getMap();
  43. }
  44. /* Return a list of sobject fields that are viewable by this user
  45. * (i.e. isAccessible() returns true)
  46. * This is the optimized version when the fieldMap is already available
  47. */
  48. public List<Schema.SObjectField> getViewableFields(Map<String,Schema.SObjectField> fieldsMap) {
  49. List<Schema.SObjectField> fields = new List<Schema.SObjectField>{};
  50. for(String key:fieldsMap.keySet()) {
  51. if(fieldsMap.get(key).getDescribe().isAccessible()) {
  52. fields.add(fieldsMap.get(key));
  53. }
  54. }
  55. return fields;
  56. }
  57. /* Return a list of sobject fields that are viewable by this user
  58. */
  59. public List<Schema.SObjectField> getViewableFields(SObjectType someType) {
  60. Map<String,Schema.SObjectField> fieldsMap = getFieldMap(someType);
  61. return getViewableFields(fieldsMap);
  62. }
  63. public List<Schema.SObjectField> getViewableFields(SObject sobj) {
  64. return getViewableFields(sobj.getSObjectType());
  65. }
  66. public void assertAuthorizedToView(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  67. checkAuthorizedToView(someType, fields, true);
  68. }
  69. public void assertAuthorizedToCreate(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  70. checkAuthorizedToCreate(someType, fields, true);
  71. }
  72. public void assertAuthorizedToUpdate(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  73. checkAuthorizedToUpdate(someType, fields, true);
  74. }
  75. public void assertAuthorizedToCreate(Schema.SObjectType someType, List<String> fields) {
  76. checkAuthorizedToCreate(someType, fields, true);
  77. }
  78. public void assertAuthorizedToUpdate(Schema.SObjectType someType, List<String> fields) {
  79. checkAuthorizedToUpdate(someType, fields, true);
  80. }
  81. public Boolean isAuthorizedToView(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  82. return checkAuthorizedToView(someType, fields, false);
  83. }
  84. public Boolean isAuthorizedToView(Schema.SObjectType someType, List<String> fieldNames) {
  85. return checkAuthorizedToView(someType, fieldNames, false);
  86. }
  87. public Boolean isAuthorizedToUpdate(Schema.SObjectType someType, List<String> fieldNames) {
  88. return checkAuthorizedToUpdate(someType, fieldNames, false);
  89. }
  90. public Boolean isAuthorizedToUpdate(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  91. return checkAuthorizedToUpdate(someType, fields, false);
  92. }
  93. public Boolean isAuthorizedToCreate(Schema.SObjectType someType, List<String> fieldNames) {
  94. return checkAuthorizedToCreate(someType, fieldNames, false);
  95. }
  96. public Boolean isAuthorizedToCreate(Schema.SObjectType someType, List<Schema.SObjectField> fields) {
  97. return checkAuthorizedToCreate(someType, fields, false);
  98. }
  99. Boolean checkAuthorizedToCreate(Schema.SObjectType someType, List<String> fieldNames, Boolean throwException) {
  100. Schema.DescribeSObjectResult objDesc = someType.getDescribe();
  101. if (!objDesc.isCreateable()){
  102. //SurveyForceUtil.log('checkAuthorizedToCreate - Object: ' + someType + ' is not createable');
  103. if (throwException) {
  104. throw new SFDCAccessControlException('Access Violation',
  105. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  106. SFDCAccessControlException.ExceptionReason.NO_CREATE,
  107. someType.getDescribe().getName(),
  108. null);
  109. } else {
  110. return false;
  111. }
  112. }
  113. Map<String, Schema.SObjectField> fMap = someType.getDescribe().fields.getMap();
  114. //SurveyForceUtil.log('checkAuthorizedToCreate - FieldMap: ' + fMap.keySet());
  115. for (String f : fieldNames) {
  116. Schema.SObjectField sObjectFld = fMap.get(f);
  117. if (sObjectFld == null) {
  118. //SurveyForceUtil.log('checkAuthorizedToCreate - Field: ' + f + ' is null');
  119. throw new SFDCAccessControlException('Field not found',
  120. SFDCAccessControlException.ExceptionType.FIELD_NOT_FOUND,
  121. SFDCAccessControlException.ExceptionReason.GENERIC,
  122. objDesc.getName(),
  123. f);
  124. }
  125. if (!sObjectFld.getDescribe().isCreateable()){
  126. //SurveyForceUtil.log('checkAuthorizedToCreate - Field: ' + f + ' is not createable');
  127. if (throwException) {
  128. throw new SFDCAccessControlException('Access Violation',
  129. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  130. SFDCAccessControlException.ExceptionReason.NO_CREATE,
  131. someType.getDescribe().getName(),
  132. sObjectFld.getDescribe().getName());
  133. } else {
  134. return false;
  135. }
  136. }
  137. }
  138. //SurveyForceUtil.log('checkAuthorizedToCreate - Type: ' + someType + ' fieldNames ' + fieldNames + ' are createable');
  139. return true;
  140. }
  141. public Boolean checkAuthorizedToCreate(Schema.SObjectType someType, List<Schema.SObjectField> fields, Boolean throwException) {
  142. // check at object-level first
  143. if (!someType.getDescribe().isCreateable()){
  144. //SurveyForceUtil.log('checkAuthorizedToCreate - Object: ' + someType + ' is not createable');
  145. if (throwException) {
  146. throw new SFDCAccessControlException('Access Violation',
  147. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  148. SFDCAccessControlException.ExceptionReason.NO_CREATE,
  149. someType.getDescribe().getName(),
  150. null);
  151. } else {
  152. return false;
  153. }
  154. }
  155. // check each field
  156. for (Schema.SObjectField f : fields) {
  157. //SurveyForceUtil.log('checkAuthorizedToCreate - Field: ' + f );
  158. if (!f.getDescribe().isCreateable()){
  159. //SurveyForceUtil.log('checkAuthorizedToCreate - Field: ' + f + ' is not createable');
  160. if (throwException) {
  161. throw new SFDCAccessControlException('Access Violation',
  162. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  163. SFDCAccessControlException.ExceptionReason.NO_CREATE,
  164. someType.getDescribe().getName(),
  165. f.getDescribe().getName());
  166. } else {
  167. return false;
  168. }
  169. }
  170. }
  171. //SurveyForceUtil.log('checkAuthorizedToCreate - Type: ' + someType + ' fields ' + fields + ' are createable');
  172. return true;
  173. }
  174. /* Returns a list of sobject fields that are updateable by this user.
  175. * This is the optimized version when the fieldMap is already available
  176. */
  177. public List<Schema.SObjectField> getUpdateableFields(Map<String,Schema.SObjectField> fieldsMap) {
  178. List<Schema.SObjectField> fields = new List<Schema.SObjectField>{};
  179. for(String key:fieldsMap.keySet()) {
  180. if(fieldsMap.get(key).getDescribe().isUpdateable()) {
  181. fields.add(fieldsMap.get(key));
  182. }
  183. }
  184. return fields;
  185. }
  186. /* Returns a list of sobject fields that are updateable by this user.
  187. */
  188. public List<Schema.SObjectField> getUpdateableFields(SObjectType someType) {
  189. Map<String,Schema.SObjectField> fieldsMap = getFieldMap(someType);
  190. return getUpdateableFields(fieldsMap);
  191. }
  192. public List<Schema.SObjectField> getUpdateableFields(SObject sobj) {
  193. return getUpdateableFields(sobj.getSObjectType());
  194. }
  195. /* Returns a list of sobject fields that are createable by this user
  196. * This is the optimized version when the fieldMap is already available
  197. */
  198. public List<Schema.SObjectField> getCreatableFields(Map<String,Schema.SObjectField> fieldsMap) {
  199. List<Schema.SObjectField> fields = new List<Schema.SObjectField>{};
  200. for(String key:fieldsMap.keySet()) {
  201. if(fieldsMap.get(key).getDescribe().isCreateable()) {
  202. fields.add(fieldsMap.get(key));
  203. }
  204. }
  205. return fields;
  206. }
  207. public List<Schema.SObjectField> getCreatableFields(SObject sobj) {
  208. return getCreatableFields(sobj.getSObjectType());
  209. }
  210. public List<Schema.SObjectField> getCreatableFields(SObjectType someType) {
  211. Map<String,Schema.SObjectField> fieldsMap = getFieldMap(someType);
  212. return getCreatableFields(fieldsMap);
  213. }
  214. /*
  215. * Check to see if the user can delete this object type.
  216. */
  217. public Boolean isAuthorizedToDelete(Schema.SObjectType someType) {
  218. // we only need to check CRUD
  219. return someType.getDescribe().isDeletable();
  220. }
  221. public Boolean assertAuthorizedToDelete(Schema.SObjectType someType) {
  222. if(!someType.getDescribe().isDeletable()) {
  223. throw new SFDCAccessControlException('Access Violation',
  224. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  225. SFDCAccessControlException.ExceptionReason.NO_DELETE,
  226. someType.getDescribe().getName(),
  227. null);
  228. }
  229. return true;
  230. }
  231. public Boolean checkAuthorizedToView(Schema.SObjectType someType, List<Schema.SObjectField> fields, Boolean throwException) {
  232. // check at object-level first
  233. if (!someType.getDescribe().isAccessible()){
  234. if (throwException) { throw new SFDCAccessControlException('Object Access Violation',
  235. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  236. SFDCAccessControlException.ExceptionReason.NO_READ,
  237. someType.getDescribe().getName(),
  238. null);
  239. } else { return false;
  240. }
  241. }
  242. // check each field
  243. for (Schema.SObjectField f : fields) {
  244. if (!f.getDescribe().isAccessible()){
  245. if (throwException) { throw new SFDCAccessControlException('Field Access Violation',
  246. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  247. SFDCAccessControlException.ExceptionReason.NO_READ,
  248. someType.getDescribe().getName(),
  249. f.getDescribe().getName());
  250. } else {
  251. System.debug('Field accessible: ' + someType.getDescribe().getName() + ' ' + f.getDescribe().getName());
  252. return false; }
  253. }
  254. }
  255. return true;
  256. }
  257. public Boolean checkAuthorizedToView(Schema.SObjectType someType, List<String> fieldNames, Boolean throwException) {
  258. Schema.DescribeSObjectResult objDesc = someType.getDescribe();
  259. if (!objDesc.isAccessible()){
  260. if (throwException) { throw new SFDCAccessControlException('Access Violation',
  261. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  262. SFDCAccessControlException.ExceptionReason.NO_READ,
  263. someType.getDescribe().getName(),
  264. null);
  265. } else { return false; }
  266. }
  267. Map<String, Schema.SObjectField> fMap = someType.getDescribe().fields.getMap();
  268. for (String f : fieldNames) {
  269. Schema.SObjectField sObjectFld = fMap.get(f);
  270. if (sObjectFld == null) {
  271. throw new SFDCAccessControlException('Field not found',
  272. SFDCAccessControlException.ExceptionType.FIELD_NOT_FOUND,
  273. SFDCAccessControlException.ExceptionReason.GENERIC,
  274. objDesc.getName(),
  275. f);
  276. }
  277. if (!sObjectFld.getDescribe().isAccessible()){
  278. if (throwException) { throw new SFDCAccessControlException('Access Violation',
  279. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  280. SFDCAccessControlException.ExceptionReason.NO_READ,
  281. someType.getDescribe().getName(),
  282. sObjectFld.getDescribe().getName());
  283. } else { return false;
  284. }
  285. }
  286. }
  287. return true;
  288. }
  289. Boolean checkAuthorizedToUpdate(Schema.SObjectType someType, List<Schema.SObjectField> fields, Boolean throwException) {
  290. // check at object-level first
  291. if (!someType.getDescribe().isUpdateable()){
  292. if (throwException) {
  293. throw new SFDCAccessControlException('Access Violation',
  294. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  295. SFDCAccessControlException.ExceptionReason.NO_UPDATE,
  296. someType.getDescribe().getName(),
  297. null);
  298. } else {
  299. return false;
  300. }
  301. }
  302. // check each field
  303. for (Schema.SObjectField f : fields) {
  304. if (!f.getDescribe().isUpdateable()){
  305. if (throwException) {
  306. throw new SFDCAccessControlException('Access Violation',
  307. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  308. SFDCAccessControlException.ExceptionReason.NO_UPDATE,
  309. someType.getDescribe().getName(),
  310. f.getDescribe().getName());
  311. } else {
  312. return false;
  313. }
  314. }
  315. }
  316. return true;
  317. }
  318. Boolean checkAuthorizedToUpdate(Schema.SObjectType someType, List<String> fieldNames, Boolean throwException) {
  319. Schema.DescribeSObjectResult objDesc = someType.getDescribe();
  320. if(!objDesc.isUpdateable()){
  321. if (throwException) {
  322. throw new SFDCAccessControlException('Access Violation',
  323. SFDCAccessControlException.ExceptionType.OBJECT_ACCESS_VIOLATION,
  324. SFDCAccessControlException.ExceptionReason.NO_UPDATE,
  325. someType.getDescribe().getName(),
  326. null);
  327. } else {
  328. return false;
  329. }
  330. }
  331. Map<String, Schema.SObjectField> fMap = someType.getDescribe().fields.getMap();
  332. for (String f : fieldNames) {
  333. Schema.SObjectField sObjectFld = fMap.get(f);
  334. if (sObjectFld == null) {
  335. throw new SFDCAccessControlException('Field not found',
  336. SFDCAccessControlException.ExceptionType.FIELD_NOT_FOUND,
  337. SFDCAccessControlException.ExceptionReason.GENERIC,
  338. objDesc.getName(),
  339. f);
  340. }
  341. if (!sObjectFld.getDescribe().isUpdateable()){
  342. if (throwException) {
  343. throw new SFDCAccessControlException('Access Violation',
  344. SFDCAccessControlException.ExceptionType.FIELD_ACCESS_VIOLATION,
  345. SFDCAccessControlException.ExceptionReason.NO_UPDATE,
  346. someType.getDescribe().getName(),
  347. sObjectFld.getDescribe().getName());
  348. } else {
  349. return false;
  350. }
  351. }
  352. }
  353. return true;
  354. }
  355. }