The only effect that "with sharing" has is to enforce object sharing rules; that is, if you use "with sharing" and query an object that has private record visibility, any Apex SOQL will only return results for objects shared to them; if you do not use "with sharing", the Apex SOQL will return results for all objects.
As VNE_Hess stated, the user's license restrictions are always enforced no matter what; you can't directly get around them when the code is executing as that user.
It's also worth mentioning that although Apex never enforces field-level and CRUD security, most of the standard VisualForce rendering components do enforce FLS/CRUD, so even though your system-context Apex was able to retrieve (and modify, etc) a field that the user doesn't have profile visibility to, if you pass it to VF via say an inputfield component, the user won't see it.
The Sites Guest User is a special profile that is heavily restricted from making updates to core CRM objects. From memory I think it's read-create only to the core objects except for Articles. Salesforce imposes this restriction AFAICT to require customers to upgrade to more expensive Partner or Customer Portal licenses to get this level of access.
If you're developing AppExchange apps that deal with the standard objects, it's very important to understand that to pass security review, your Apex code must manually enforce FLS and CRUD at every step of the way. This is a HUGE pain in the rear if your app does a lot of these updates, and results in very error-prone code because the ESAPI toolkit that Salesforce provides has a much more error-prone API than the core SOQL/DML interface.
Salesforce would save its app developer community literally thousands of hours of work per year by implementing a "with FLSAndCrud" type keyword, but architecturally that seems unlikely any time soon.
Process Builder runs "as the user", but with "system permissions." This means it can perform operations the user normally couldn't. As such, I think the easiest way to do this would be to write the validation rule as:
NOT(ISNEW()) && ISBLANK(NeededField__c)
Have NeededField be read-only for the user so they can't manually manipulate the record into being editable ahead of time.
As a related concept, perhaps you could use a short trigger to just lock the record:
trigger onObjectX on ObjectX (after insert, after update) {
ObjectX[] locks = new Object[0], unlocks = new ObjectX[0];
for(ObjectX record: Trigger.new) {
if(record.NeededField__c == null) {
locks.add(record);
} else {
unlocks.add(record);
}
}
Approval.lock(locks, false);
Approval.unlock(unlocks, false);
}
I'm pretty sure there's other alternatives as well of various complexity, but I hope one of these will help you.
Best Answer
According to this answer: