Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 6eb5c69

Browse files
authored
Update identity store spec text after EG call
1 parent 3d0dba9 commit 6eb5c69

File tree

1 file changed

+33
-33
lines changed

1 file changed

+33
-33
lines changed

src/main/doc/identityStore.asciidoc

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,11 @@ This chapter describes the _IdentityStore_ and _IdentityStoreHandler_ interfaces
147147

148148
=== Introduction
149149

150-
_IdentityStore_ provides an abstraction of a user store. Implementations of the interface are used to interact with user stores to authenticate users, and to retrieve users' groups.
150+
_IdentityStore_ provides an abstraction of an identity store, which is a database (store) for storing (identity) data related to callers (users), specifically their credentials and their association with the abstract notion of a "group". Implementations of the interface are used to interact with identity stores to authenticate users (validate their credentials), and to retrieve users' groups. _IdentityStore_ is roughly equivalent to how the JAAS _LoginModule_ is often integrated in Java EE products in a vendor specific way, but is specifically targetted on Java EE and more focussed on only providing the credential validation and group retrieval (see below).
151151

152-
_IdentityStore_ is intended primarily for use by _HttpAuthenticationMechanism_ implementations, but could in theory be used by other types of authentication modules (e.g., _ServerAuthModule_ or _LoginModule_). _HttpAuthenticationMechanism_ implementations are not required to use _IdentityStore_ -- they can authenticate users in any manner they choose -- but _IdentityStore_ will often be a useful and convenient mechanism.
152+
_IdentityStore_ is in this version of the spec intended primarily for use by _HttpAuthenticationMechanism_ implementations, but could in theory be used by other types of authentication mechanisms (e.g., the JASPIC _ServerAuthModule_ or the Servlet build-in authentication mechanisms such as FORM). _HttpAuthenticationMechanism_ implementations are not required to use _IdentityStore_ -- they can authenticate users in any manner they choose -- but _IdentityStore_ will often be a useful and convenient mechanism.
153153

154-
A primary advantage of using _HttpAuthenticationMechanism_ and _IdentityStore_ over container-provided BASIC or FORM implementations is that it allows an application to control the user stores it will authenticate against, in a standard, portable way.
154+
A primary advantage of using _HttpAuthenticationMechanism_ and _IdentityStore_ over container-provided BASIC or FORM implementations is that it allows an application to control the identity stores it will authenticate against, in a standard, portable way.
155155

156156
An _IdentityStore_ MUST only perform environment-independent security processing (for example, verifying a username/password that was passed in to it as a String/char array, and returning the caller data). In other words, the _IdentityStore_ MUST NOT directly interact with the caller, and SHOULD perform a pure _{credentials in, caller data out}_ function. It MUST NOT attempt to, e.g., get a request parameter or cookie from the _HttpServletRequest_.
157157

@@ -161,18 +161,12 @@ A default _IdentityStoreHandler_ implementation is supplied by the container, bu
161161

162162
=== Interface and Theory of Operation
163163

164-
The _IdentityStore_ interface defines two methods that are used by the runtime to validate a _Credential_ or obtain user information:
164+
The _IdentityStore_ interface defines two methods that are used by the runtime to validate a _Credential_ or obtain caller information:
165165

166166
* validate(Credential)
167167
* getGroupsByCallerPrincipal(CallerPrincipal)
168168

169-
An implementation of _IdentityStore_ MAY support either one, or both, of the methods, depending on whether the _IdentityStore_ provides AUTHENTICATION, AUTHORIZATION, or BOTH. Authentication means that the _IdentityStore_ can validate a caller's credential, thus authenticating the user. Authorization means that the _IdentityStore_ can (separately from validation) retrieve caller attributes (i.e., groups) for use in authorization decisions. Both means that the _IdentityStore_ can perform both functions.
170-
171-
****
172-
*Review:*
173-
174-
Would "user groups", "user attributes", "user info", "user data", or similar, be a better abstraction concept than "authorization" for the _getCallerGroups()_ method? While, ultimately, the purpose of obtaining user groups is to use them as the basis for authorization decisions, the method in question does not really perform authorization, nor does any other part of _IdentityStore_.
175-
****
169+
An implementation of _IdentityStore_ MAY be configured such, or indicate, that only one of those methods or both are used by the container. This is done by returning either or both VALIDATE and PROVIDE_GROUPS from the _validationTypes_ method. VALIDATE means that the _IdentityStore_ can validate a caller's credential, thus authenticating the caller (user). PROVIDE_GROUPS means that the _IdentityStoreHandler_ will use the groups returned by the store, either the ones from the result of calling _validate_ or by calling _getGroupsByCallerPrincipal_ separately. Note that the _validationTypes_ method can thus be used in 2 ways; when the outcome is configurable it is primarily used to set what the store should be used for, independent of what the store is capable of, when the outcome is not configurable it is primarily used to indicate what the store is capable of.
176170

177171
==== Validating Credentials
178172

@@ -206,6 +200,9 @@ The defined status values are:
206200
*Review:*
207201
208202
Should we define additional an error code to indicate that validation was attempted, but failed due to network error, server down, or other error not related to the credential's validity? I.e., as distinct from either INVALID, or NOT_VALIDATED?
203+
204+
*Reply:*
205+
In such cases an Exception will be thrown
209206
****
210207

211208
The _Credential_ interface is a generic interface capable of representing any kind of token or user credential. An _IdentityStore_ implementation can support multiple concrete _Credential_ types, where a concrete _Credential_ is an implementation of the _Credential_ interface that represents a particular type of credential. It can do so by implementing the validate(Credential)_ method and testing the type of the _Credential_ that's passed in; however, as a convenience, the _IdentityStore_ interface provides a default implementation of _validate(Credential)_ that delegates to a method that handles the specific type of _Credential_, if provided by _IdentityStore_ implementation:
@@ -251,7 +248,7 @@ The _getGroupsByCallerPrincipal()_ method retrieves the set of groups associated
251248
List<String> getGroupsByCallerPrincipal(CallerPrincipal callerPrincipal);
252249
----
253250

254-
The _getGroupsByCallerPrincipal()_ method supports aggregation of identity stores, where one identity store is used to authenticate users, but another store -- or multiple other stores -- is used to retrieve additional user attributes. In such a scenario, it is necessary to query some identity stores without validating a user credential.
251+
The _getGroupsByCallerPrincipal()_ method supports aggregation of identity stores, where one identity store is used to authenticate users, but another store -- or multiple other stores -- is used to retrieve additional groups. In such a scenario, it is necessary to query some identity stores without validating a caller credential.
255252

256253
Note that _getGroupsByCallerPrincipal()_ is not intended as a general purpose API for retrieving user groups. It MUST be called only by an _IdentityStoreHandler_, in the course of orchestrating a _validate()_ call across multiple identity stores.
257254

@@ -262,7 +259,7 @@ As a result, it is never necessary to call _getGroupsByCallerPrincipal()_ when t
262259
****
263260
*Review:*
264261
265-
* Should the returned groups be a Set (rather than a List)? Here, and for the validate() call as well?
262+
*
266263
267264
Several concerns have been raised about this interface. One is that CallerPrincipal is not guaranteed to be unique. If it is not, then passing in, e.g., "foo", could result in the wrong set of groups being returned -- granting illegitimate privileges, denying legitimate privileges, or both. Hopefully developers, architects, and system admins work to ensure that local user stores don't include overloaded names, but it may be overly optimistic to assume they will always get it right in complex, heterogenous environments. Moreover, environments often change over time, and may drift away from the originally specified and implemented constraints, particularly if the constraints aren't well-documented. Overall, it seems fragile to rely on that for security.
268265
@@ -275,27 +272,28 @@ Similarly, the second issue can be addressed by making the method privileged, so
275272

276273
==== Declaring Capabilities
277274

278-
The _IdentityStore_ interface includes methods for an implementation to declare its capabilities and ordinal priority.
275+
The _IdentityStore_ interface includes methods for an implementation to declare its capabilities and ordinal priority. An _IdentityStore_ implementation MAY allow these "capabilities" to be configured, so that an application can determine what a store is used for.
279276

280277
[source,java]
281278
----
282-
enum ValidationType { AUTHENTICATION, AUTHORIZATION, BOTH };
279+
enum ValidationType { VALIDATE, PROVIDE_GROUPS };
280+
Set<ValidationType> DEFAULT_VALIDATION_TYPES =
281+
EnumSet.of(VALIDATE, PROVIDE_GROUPS);
283282
284283
default int priority() {
285284
return 100;
286285
}
287286
288-
default ValidationType validationType() {
289-
return BOTH;
287+
default Set<ValidationType> validationTypes() {
288+
return DEFAULT_VALIDATION_TYPES;
290289
}
291290
----
292291

293-
The _validationType()_ method returns a value indicating whether the _IdentityStore_ performs authentication, authorization (get groups), or both. The _priority()_ method allows the implementation to declare a priority, used for ordering invocations when multiple _IdentityStore_ instances are present.
292+
The _validationTypes()_ method returns a Set indicating whether the _IdentityStore_ performs validation, provides groups or both. The _priority()_ method allows the implementation to declare a priority, used for ordering invocations when multiple _IdentityStore_ instances are present.
294293

295294
****
296295
*Review:*
297296
298-
* Would separate _isAuthentication()/isAuthorization()_ methods make for simpler implementations of both _IdentityStore_ and _IdentityStoreHandler_ than does _validationType()_ with an enum? The annotations do it that way.
299297
* Is 1 (or 0) a better choice of default priority? Any choice is arbitrary (and equally like to conflict with others), but a lower number seems like it would more often be the desired value.
300298
****
301299

@@ -314,21 +312,21 @@ The purpose of the _IdentityStoreHandler_ is to allow for multiple identity stor
314312

315313
The _validate()_ method of the default implementation MUST do the following:
316314

317-
* Call the _validate(Credential credential)_ method on all available _IdentityStore_ beans that declared themselves capable of doing authentication, in the order induced by the return value of the _getPriority()_ method of each _IdentityStore_ (lower values imply a lower order, causing the corresponding _validate(Credential credential)_ method to be called sooner).
315+
* Call the _validate(Credential credential)_ method on all available _IdentityStore_ beans that declared themselves capable of doing validation, in the order induced by the return value of the _getPriority()_ method of each _IdentityStore_ (lower values imply a lower order, causing the corresponding _validate(Credential credential)_ method to be called sooner).
318316
** If a call to _validate()_ returns a result with status _INVALID_, remember this result.
319317
** If a call to _validate()_ returns a result with status _VALID_, remember this result and stop calling the _IdentityStore_ beans.
320318
* If all _IdentityStore_ beans have been called but no result was returned with status _VALID_, then:
321319
** If a result was previously returned with status _INVALID_, return that result.
322320
** Otherwise, return a result with status _NOT_VALIDATED_.
323-
* If we have a _VALID_ result, call the _getGroupsByCallerPrincipal(CallerPrincipal callerPrincipal)_ method on all available _IdentityStore_ beans that declared themselves capable of doing _only_ authorization, in the order induced by the return value of the _getPriority_ method of each _IdentityStore_. The _CallerPrincipal_ passed in to this method is the _CallerPrincipal_ obtained from the result of the successful call to _validate()_ in the previous phase.
324-
* Return a new _CredentialValidationResult_ with status _VALID_, the _CallerPrincipal_ that was used in each call to the _getGroupsByCallerPrincipal()_ method, and the collection of groups that is the combination of the groups returned by the result of the _validate(Credential credential)_ call for which _getStatus()_ returned _VALID_ and all of the groups returned by each call to the _getGroupsByCallerPrincipal_ method.
321+
* If we have a _VALID_ result, then if and only if the identity store from which the _VALID_ result originated declared to provide groups, take its groups from the result.
322+
* Next call the _getGroupsByCallerPrincipal(CallerPrincipal callerPrincipal)_ method on all available _IdentityStore_ beans that declared themselves capable of _only_ providing groups, in the order induced by the return value of the _getPriority_ method of each _IdentityStore_. The _CallerPrincipal_ passed in to this method is the _CallerPrincipal_ obtained from the result of the successful call to _validate()_ in the previous phase.
323+
* Return a new _CredentialValidationResult_ with status _VALID_, the _CallerPrincipal_ that was used in each call to the _getGroupsByCallerPrincipal()_ method, and the collection of groups that is the combination of the groups returned by the result of the _validate(Credential credential)_ call for which _getStatus()_ returned _VALID_ (if applicable) and all of the groups returned by each call to the _getGroupsByCallerPrincipal_ method.
325324

326325
****
327326
*Review:*
328327
329-
* In the last bullet above, do we need to specify a "new" _CredentialValidationResult_? Could an implementation not simply add groups to the previous _VALID_ result?
330-
* This usage model might be better served by having _getGroupsByCallerPrincipal()_ return a Set, rather than a list. I believe Set semantics are what we want -- Subjects contain a Principal Set, and each group principal should appear only once.
331-
* If we distinguish the case of "error" (i.e., network problem, server down, timeout, etc.) from the case of "invalid credential" and "credential type not handled" we'll need to adjust the logic of what to return when no _VALID_ result was obtained.
328+
* In the last bullet above, do we need to specify a "new" _CredentialValidationResult_? Could an implementation not simply add groups to the previous _VALID_ result? (no, _CredentialValidationResult_ is immutable).
329+
* If we distinguish the case of "error" (i.e., network problem, server down, timeout, etc.) from the case of "invalid credential" and "credential type not handled" we'll need to adjust the logic of what to return when no _VALID_ result was obtained. (for an error, an exception will be thrown)
332330
****
333331

334332
==== State
@@ -339,6 +337,9 @@ An _IdentityStore_ is logically stateless. An _IdentityStoreHandler_ SHOULD NOT
339337
*Review:*
340338
341339
Is the above restriction reasonable? By definition, the validate() method will know that the user is unauthenticated, because the method wouldn't be called otherwise. Similarly, getGroupsByCallerPrincipal() will know that the user is already authenticated when it is called. Agree with the notion that _IdentityStoreHandler_ handler shouldn't assume, or try to inspect, the state of an _IdentityStore_, and, likewise, that _IdentityStore_ shouldn't assume anything about the state or behavior of its caller, but the language may need to be looser -- it seems impossible to comply with as written.
340+
341+
*Answer:*
342+
The wording means that the _IdentityStore_ represents something that has state (e.g. a DataBase) but calls to it are essentially functional. This is mostly to make clear identity stores are only used to query, and they are not aware of things like a caller being authenticated, currently logged-in, stored in the http session, etc. These all are concerns of the specific environment in which the store is used. "the validate() method will know that the user is unauthenticated" - it's not really *know* but more *assume*. Indeed, validate() *should* only be called if the caller is unauthenticated, but it should not keep track of this internally. In other words, an IdentityStore implementation should theoretically be possile by using an @Stateless EJB bean.
342343
****
343344

344345
An _IdentityStore_ instance MAY make use of instance variables; for example, to store configuration data like an LDAP URL, to store actual caller data for in-memory lookup, for the caching, etc.
@@ -354,17 +355,20 @@ As described above, the _IdentityStore_ interface defines two methods that are u
354355
[source,java]
355356
----
356357
int priority()
357-
ValidationType validationType()
358+
Set<ValidationType> validationTypes()
358359
----
359360

360361
The _priority()_ method allows an _IdentityStore_ to be configured with an ordinal number that indicates in which order an _IdentityStore_ is consulted in case multiple ones are present, or more exactly when multiple enabled CDI Beans with type _IdentityStore_ are available. A lower value returned here means that _IdentityStore_ is called before an _IdentityStore_ returning a higher value. The order of being called is undefined when two _IdentityStore_ implementations return the same value.
361362

362-
The _validationType()_ method returns an enum constant of type _ValidationType_, that indicates if an _IdentityStore_ is to be used for authentication only (meaning any group data it returns must be ignored), for authorization only (meaning it's not used for authentication, but only to obtain the group data from if the caller is authenticated via other means), or both (meaning it's used for authentication and any group data it returns is used).
363+
The _validationTypes()_ method returns a Set with enum constants of type _ValidationType_, that indicate if an _IdentityStore_ is to be used for authentication only (meaning any group data it returns must be ignored), for providing groups only (meaning it's not used for authentication, but only to obtain the group data from if the caller is authenticated via other means), or both (meaning it's used for authentication and any group data it returns is used).
363364

364365
****
365366
*Review:*
366367
367368
May want to omit the language above saying group data from an authentication-only _IdentityStore_ must be ignored -- it seems unnecessary and confusing. An _IdentityStore_ that doesn't want to return group data during validation can choose not return it. If it does return group data during validation, the groups should be accepted, regardless of the declared validationType. The purpose of type "authentication", as opposed to "authorization" or "both", is to indicate that the _IdentityStore_ should not be called during the second (authorization) phase of the "validate()" processing.
369+
370+
*Answer:*
371+
No, this part is crucial, as discussed during the EG meeting. The key here is that an _IdentityStore_ does not just use the validation types to indicate what it's capable of, but can also be configured that way to indicate what it should be used for. The goal is to leave the identity stores as simple as can be, and move any complexity to the handler.
368372
****
369373

370374
=== Annotations and Built-In IdentityStore Beans
@@ -416,9 +420,7 @@ public @interface LdapIdentityStoreDefinition {
416420
417421
int priority() default 80;
418422
419-
boolean authenticateOnly() default false;
420-
421-
boolean authorizeOnly() default false;
423+
ValidationType[] useFor() default {VALIDATE, PROVIDE_GROUPS};
422424
}
423425
----
424426

@@ -442,9 +444,7 @@ public @interface DataBaseIdentityStoreDefinition {
442444
443445
int priority() default 70;
444446
445-
boolean authenticateOnly() default false;
446-
447-
boolean authorizeOnly() default false;
447+
ValidationType[] useFor() default {VALIDATE, PROVIDE_GROUPS};
448448
}
449449
----
450450

0 commit comments

Comments
 (0)