Identity provider extensibility

* Mark interface implementation methods as `virtual`
* Expose `private` fields in `CloudIdentityProvider` as `protected` properties
* Include the identity endpoint URL in the token cache key, so multiple cloud instances can be used in the same process with the same username