Security Objects
Warning
This document needs an update to describe the role of realms.
In release 237, the security subsystem was refactored and IUserAccount was added to the optional account-entities component. Post-refactor, there are several concepts that participate in determining the user identity which is part of an user's principal.
Identities
An <xref:The.Security.Identity> object contains a username and optionally some claims. Not all identities have been authenticated. SecurityService produces <xref:The.Security.IPrincipal> implementations which contain either an authenticated Identity or an AuthenticationFailure error code, but an application is free to construct identities (and principals) in other ways. However, the identity is supplied to IEntityStore when executing read/write operations, and some entity stores will only accept an identity which they can verify, including the mutual-authentication process used by RemoteEntityStore and the verification of Windows accounts used by SQLEntityStore with Integrated Security.
Identity Usernames
A username is a short string which identifies a user to external systems. Entity stores record the username in modifiedOn/createdOn columns and in optional audit entities. It's provided to ASP.NET Core's Identity subsystem and to Blazor's AuthenticationState.
In The.Core, the concept of username uniqueness doesn't apply, because usernames are data and have no reference-equality of their own. However, many external systems require or prefer uniqueness.
Within the security subsystem, the name subject is sometimes used to refer to a user identity being produced or checked. A subject is sometimes just a username and sometimes a whole Identity.
Identity Claims
The claims in an identity are key-value pairs representing extra security facts about a user. For example, the claim {"pki", "5362EA0D-8EBF-400D-A810-C32E3C847C28"} is used by PKIAuthentication to mean that an ePass2003 token with the guid above is registered for this identity. Claims have no inherent meaning and are interpreted only by specific instantiations of the security protocol - particular implementations of IEntityStore, IAuthentication and IAuthorisation.
User Accounts
The "user accounts" optional model component adds three synthetic entities implementing IUserAccount, IUserClaim and IUserProfile. UserProfile has no security relevance, but UserAccount and UserClaim correspond roughly to the username and claims parts of an identity.
When using accounts, the IUserAccount.Username attribute is a user's canonical username, which may differ from the realm-specific username returned by any given authenticator. A claim contains extra security properties, including authenticator-specific data and role information for authorisation.
Local Authentication
SecurityService requests an 'ambient' identity from the configured authenticator. (As of release 241, the authenticator just provides a username, and SecurityService synthesises a Claim based on the authenticator's Realm). This is enough to create an Identity object which is considered "local" and unverified. There are two ways for authentication to proceed from here:
- Some authenticators are "authoritative", meaning that they produce identities which can be checked locally without remote validation. (For example,
WebAuthenticationandBlazorAuthentication, which derive identity from external authentication systems that may in turn chain back to framework authentication). The asserted identity is given toIAuthentication.VerifyIdentity, and if it passes, you're authenticated. - If the authenticator is not authoritative, the entity store gets to weigh in.
IEntityStore.ConnectAsync() is called; if it fails you aren't authenticated, but if it succeeds, the entitystore may optionally indicate that it authenticated you as a particular username, which overrides the ambient username already supplied. This allows stores to canonicalise or merge identities - the same user may have both a password and an HTTP cookie, both of which resolve to the same account. If the entity store didn't perform remote verification,IAuthentication.VerifyIdentityis called instead.
Remote Authentication
When using RemoteEntityStore, the server and client choose an AuthenticationProtocol based on signing each operation, encrypting a session key, or both - different authenticators have different feature sets. A A remote Endpoint running on the server calls authenticator methods with the Identity provided by the client. Remote authenticators typically require user accounts; they use the supplied identity's Claims to determine an Account, then encrypt data for or check signatures by the resolved identity.
For example, accounts created by PasswordAuthentication have three names: logon name, hash and salt. If using AuthenticationProtocol.EncryptedOperations, the authenticator will look up an IUserAccount by its logon name claim, determining an account username and the other two claims. It then uses the hash claim and salt claim to encrypt a secret (a session key) which can only be decrypted by someone whose password hashes to the same value; the username, salt and secret are returned to the client. In RemoteEntityStore on the client side, decryption is attempted, and if successful a session is set up using the retrieved key; the authenticated username is then returned to SecurityService, which uses it to replace the ambient username in an authenticated principal.
Account Migration
Before release 237, the user accounts component had only two entities, implementing IUserProfile and IUserClaim. There was no canonical username; instead, all identities had a Realm as well as a Name. For backwards compatibility, the framework has some temporary features which get authentication data from the old paradigm working in the new world.
When the modelfile is upgraded and migrations are run, a UserAccount entity will be created for each UserProfile and the 1:m UserClaims relationship will be moved to UserAccount. The composition setting Options.RealmClaimsMigration is also on by default. If set, then when ComponentService looks up a user account, it will fall back to looking up accounts by their "realm claim" (In future, not all authenticators will have such a claim, but for now SecurityService adds one to the Identity.) This mechanism may be redundant with the SQL-based migration and needs reevaluation at some point.