What’s in a word: Quiddity

In essence, Quiddity means: the essence of a thing. (Yeah, I did that.) Within Salesforce, Quiddity refers to the essence of an Apex Transactions’ execution. Knowing the quiddity of your code allows you to customize your code at runtime. A few weeks back Shane McLaughlin, demo king and professional French Horn playa joined me. We explored how Quiddity can help you write more secure code! Missed the session? Don’t worry, you can view it on demand right here.

Wait, what’s Quiddity?

Self-referencing puns aside, Quiddity is a system provided Enum. Developers access the Quiddity value by calling getQuiddity() on the Request object. That enum is a precise indicator of what started this Apex transaction. This is like the idea behind Test.isRunningTest(). Quiddity can tell you that this code ran in an execute anonymous block, or in response to an LWC controller. Quiddity’s precision lets you know, that not only are you in a test context, but which kind of test context. (There are three!)

Quiddity has many uses. In general they focus on making choices about code execution at runtime. For instance, Quiddity can help you know what kind of Batch job you’re running. Knowing this, you could change query parameters or execute a logic block as a Queueable. This can help you avoid hitting governor limits. It can also serve as a gatekeeping function. That’s right, Quiddity can prevent the execution of code in contexts where this code is unsafe.

How does knowing the Quiddity help secure my code?

Apex runs in System Mode. It’s an often stated, but often mis-understood phrase. I’ve heard many interesting ideas about what System Mode means, but here’s the definitive truth. System mode runs Apex as the user who invoked it, but grants all, or nearly all user permissions. Additionally, System mode grants the running user CRUD and FLS to all objects. But wait, I hear some saying! “What about the class sharing modifiers like with sharing and inherited sharing?” Those are sharing modifiers, not CRUD and FLS modifiers. Even when sharing modifiers are present, System mode bypasses CRUD and FLS checks. As a developer, you need to manually check Crud and FLS before making DML calls. Libraries like Apex Recipes’ CanTheUser, or ESAPI make this easier. When you’re doing queries, make sure to use StripInaccessible() and WITH SECURITY_ENFORCED!

There are times where it’s OK to write code in a way that may, on the face of it, be unsafe. One example are QueryBuilder method(s). QueryBuilders are convenient, but can be a potential SOQLInjection hazard. If the queryBuilder method doesn’t compare a users’ FLS and CRUD manually, it’s possible to ‘leak’ fields. Because of System mode, querying for a field that the user doesn’t have access to will return that field. We can mitigate the danger, somewhat, by ensuring that the calling code is doing those checks. This isn’t perfect, because an untrusted source of input could call the queryBuilder.

We can use Quiddity to guard against a methods’ execution. When the Quiddity indicates an untrusted context, we can change the execution path. Let’s look at an example!

Quiddity Guard, an example

During the livestream, Shane and I refactored Apex Recipes’ DynamicSOQLRecipes’ class. We added a quick quiddity check to simpleQueryBuilder. The idea is simple, we want to prevent simpleQueryBuilder from running a query – sometimes. Specifically, when the Quiddity might involve unsanitized input. I’ve since extracted that into its own class and method. Let’s look at QuiddityGuard, and how it works inside our DynamicSOQLRecipes class.

Few things I want to call out here. First, by extracting this work out into its own class we have a nice place to store our custom lists of Quiddity. In this case, I’ve created a trustedQuiddities list that we can reference elsewhere. If you look at the code in Github you’ll see I’ve created a few other lists of Quiddities that might be useful.

Notice that @TestVisible private variable testQuiddityOverrride? This variable combined with the isAcceptableQuiddity() method gives our tests superpowers. Tests can inject a Quiddity value that’s different than what getQuiddity() returns. This allows us to test exactly how code responds in different Quiddity contexts!

Finally, let’s look at that isAcceptableQuiddity() method. It accepts a list of Quiddity values, but it’s not locked to the lists defined above it. Our method is reusable, even with on-the-fly custom defined lists of acceptable Quiddity. Of course, it makes sense that predefined Quiddity lists are the most likely use case. That’s why QuiddityGuard contains these predefined lists. Of course, you could also pull those lists from custom metadata (an exercise for the reader!) Note, this is where we use that testQuiddityOverride variable.

This class functions as an intelligent abstraction. It gives us a friendly API to guard against execution in unwanted Quiddity contexts. Additionally, it gives us a way to unit test code using Quiddity checks. Here’s what that looks like in our simpleQueryBuilder method:

Our QuiddityGuard class allows us to runtime-inspect how the code was executed. For Quiddity values we don’t trust, our code now returns an return an empty list of accounts.

Adopt it!

Quiddity is a powerful tool for runtime control flow. One of its use cases is to guard against code execution in untrusted contexts. i.e. where the Quiddity indicates user input, rather than vetted code defined method parameters. Doing this kind of guard helps secure your code against possible SOQLInjection vectors. Coding Quiddity checks into a reusable, encapsulated class gives us an intelligent abstraction. It provides developers an easy to understand API for ensuring our code only runs in approved contexts. It also helps us write unit tests for Quiddity using code. If you missed the session with Shane and I, feel free to view it on demand here for more details. As always, the code for QuiddityGuard, and other code is found in Apex Recipes, which you can find on Github! Check it out, give it a star, and adopt Quiddity checks in your org!

About the author

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS