To expand on our discussion around AuthenticationProvider. With the
currrent implementation of AuthenticationProvider, Keycloak admin
console cannot be used to manage external users until the user has
logged in and a UserModel creation has happened. We would need to
duplicate the "import" logic that is within AuthenticationManager
wherever UserProvider.getUserByXXXX() is invoked. Not only that, but
role mappings and other claim data may be contained in external storage.
The authentictionProvider interface is inadequate for these scenarios.
My thinking is that for federation and sync would come in three flavors:
* Keycloak storage. What we currently implement.
* Full external storage. The app developer will use their own
persistence model to store and manage users. In this case, they need to
fully implement the UserProvider interface. Handle social links,
required actions, role mappings etc.
* A sync/import model. In this case, keycloak is augmenting an existing
user storage. This would require partially or fully importing the user
from the external store into Keycloak UserModel/Provider storage. The
import is required so that Keycloak can managed REQUIRED ACTIONS, social
links, and add additional or manage existing credential types. We also
need the import to establish relationships between the user and
UserSession metadata. We may also have to handle role mappings within
Keycloak. A sync/import model example could be an LDAP store that just
contains username, email, first/last, and password. And the admin wants
to add role mappings and totp.
How would it work?
I think all this should be done through a common UserProvider interface.
Initially be able to federate only 1 additional external store as I'm
worried that there may be the possibility of duplicate user names if you
allow more than one and you'd need a way at login to pick which one to
log in from.
UserProviderFactory would specify its feature set:
Query Capabilities:
REGISTRATION
QUERY_BY_USER_ID
QUERY_BY_USERNAME
QUERY_BY_EMAIL
QUERY_BY_ATTRIBUTES
And its supported credential validation:
PASSWORD_VALIDATION
TOTP_VALIDATION
CERT_VALIDATION
And its supported credential storage:
PASSWORD_STORAGE
TOTP_STORAGE
CERT_STORAGE
There would a FederatedUserProvider to manage local and federated storage.
*Locating a user:*
1. FederatedUserProvider queries local storage first.
2. Check realm to see if federated storage configured
3. Load that provider
4. See if that provider supports query method, if not return null
5. Call query method on provider
Provider performs the following on user location:
6. Do custom query to find user
7. Get a local storage session and create a user within local storage
importing whatever can be imported.
8. Mark in local user storage which provider loaded it.
9. return the local user
*Required Actions and Credential management*
1. Find provider used to load user
2. Check credential storage options
3. If provider doesn't support credential update/storage, then store in
local storage
*Authentication*
1. Find user in local storage
2. See if credential is stored in local storage, validate from there if so.
3. If not stored, check provider validation options. Abort if not supported
4. Invoke on external provider to validate credentials supported by that
provider
Did I cover everything?
--
Bill Burke
JBoss, a division of Red Hat
http://bill.burkecentral.com