Skip to content

Commit d83c355

Browse files
committed
Added identity store content.
1 parent 3c0f461 commit d83c355

4 files changed

Lines changed: 240 additions & 13 deletions

File tree

src/main/jbake/content/partcasestudies.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ Case Studies
2020
Part XII presents case studies that use a variety of Java EE
2121
technologies. This part contains the following chapters:
2222

23-
* link:dukes-bookstore.html#GLNVI[Chapter 60, "Duke's Bookstore Case
23+
* link:dukes-bookstore.html#GLNVI[Chapter 61, "Duke's Bookstore Case
2424
Study Example"]
25-
* link:dukes-tutoring.html#GKAEE[Chapter 61, "Duke's Tutoring Case Study
25+
* link:dukes-tutoring.html#GKAEE[Chapter 62, "Duke's Tutoring Case Study
2626
Example"]
27-
* link:dukes-forest.html#GLNPW[Chapter 62, "Duke's Forest Case Study
27+
* link:dukes-forest.html#GLNPW[Chapter 63, "Duke's Forest Case Study
2828
Example"]

src/main/jbake/content/partsupporttechs.adoc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ Java EE Supporting Technologies
2020
Part XI explores several technologies that support the Java EE platform.
2121
This part contains the following chapters:
2222

23-
* link:transactions.html#BNCIH[Chapter 54, "Transactions"]
24-
* link:resources.html#BNCJH[Chapter 55, "Resource Adapters and
23+
* link:transactions.html#BNCIH[Chapter 55, "Transactions"]
24+
* link:resources.html#BNCJH[Chapter 56, "Resource Adapters and
2525
Contracts"]
26-
* link:connectorexample.html#GLODB[Chapter 56, "The Resource Adapter
26+
* link:connectorexample.html#GLODB[Chapter 57, "The Resource Adapter
2727
Examples"]
28-
* link:interceptors.html#GKEED[Chapter 57, "Using Java EE Interceptors"]
29-
* link:batch-processing.html#GKJIQ6[Chapter 58, "Batch Processing"]
30-
* link:concurrency-utilities.html#GKJIQ8[Chapter 59, "Concurrency
28+
* link:interceptors.html#GKEED[Chapter 58, "Using Java EE Interceptors"]
29+
* link:batch-processing.html#GKJIQ6[Chapter 59, "Batch Processing"]
30+
* link:concurrency-utilities.html#GKJIQ8[Chapter 60, "Concurrency
3131
Utilities for Java EE"]

src/main/jbake/content/security-api003.adoc

Lines changed: 229 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,232 @@ prev=security-api002.html
99
[[overview-of-the-identity-store-interfaces]]
1010
Overview of the Identity Store Interfaces
1111
-----------------------------------------
12-
Include a discussion about IdentityStore and IdentityStoreHandler interfaces,
13-
how to implement the default implementation, and how to create a custom identity
14-
store if desired.
12+
The Identity Store Interfaces are described in the following sections:
13+
14+
* link:#the-identitystore-interface[The IdentityStore Interface]
15+
* link:#the-identitystorehandler-interface[The IdentityStoreHandler Interface]
16+
* link:#the-passwordhash-interface[The PasswordHash Interface]
17+
* link:#the-remembermeidentitystore-interface[The RememberMeIdentityStore Interface]
18+
19+
[[the-identitystore-interface]]
20+
The IdentityStore Interface
21+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
22+
The `IdentityStore` interface defines an SPI for interacting with identity stores,
23+
which are directories or databases containing user account information.
24+
An implementation of the `IdentityStore` interface can validate users' credentials,
25+
provide information about the groups they belong to, or both. Most often, an
26+
`IdentityStore` implementation will interact with an external identity store --
27+
an LDAP server, for example -- to perform the actual credential validation and
28+
group lookups, but an `IdentityStore` may also manage user account data itself.
29+
30+
There are two built-in implementations of `IdentityStore`: an LDAP identity store,
31+
and a Database identity store. These identity stores delegate to external stores
32+
that must already exist; the IdentityStore implementations do not provide or
33+
manage the external store. They are configured with the parameters necessary
34+
to communicate with an external store using the following annotations:
35+
36+
* `LdapIdentityStoreDefinition` -- configures an identity store with the parameters
37+
necessary to communicate with an external LDAP server, validate user credentials,
38+
and/or lookup user groups.
39+
40+
* `DatabaseIdentityStoreDefinition` -- configures an identity store with the
41+
parameters necessary to connect to an external database, validate user credentials,
42+
and/or lookup user groups.
43+
44+
link:security-api004.html#running-the-built-in-database-identity-store-example[Running the Built-In Database Identity Store Example]
45+
demonstrates usage of the built-in database identity store.
46+
47+
Multiple implementations of `IdentityStore` may be present; if so, they are invoked
48+
in priority order, based on each identity store's self-declared priority and
49+
type (validation, groups, or both). An implementation of `IdentityStore` must be a
50+
CDI bean to be recognized and deployed at runtime, and is assumed to be normal scoped.
51+
IdentityStores are primarily intended for use by implementations of
52+
`HttpAuthenticationMechanisms`, but this is not a requirement.
53+
They can be used by other types of authentication mechanisms as well, or by containers.
54+
55+
[[the-identitystorehandler-interface]]
56+
The IdentityStoreHandler Interface
57+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
58+
59+
Authentication mechanisms do not interact with `IdentityStore` directly; instead,
60+
they call an `IdentityStoreHandler`. An implementation of the `IdentityStoreHandler`
61+
interface provides a single method, `validate(Credential)`, which, when invoked,
62+
iterates over the available IdentityStores and returns an aggregated result.
63+
An `IdentityStoreHandler` must also be a CDI bean, and is assumed to be normal scoped.
64+
At runtime, an authentication mechanism injects the `IdentityStoreHandler` and
65+
invokes on it. The `IdentityStoreHandler`, in turn, looks up the available IdentityStores
66+
and invokes on them to determine the aggregate result.
67+
68+
There is a built-in `IdentityStoreHandler` that implements a standard algorithm
69+
defined by JSR-375. The JSR-375 specification provides a full description of
70+
the algorithm, but it can be roughly summarized as follows:
71+
72+
* Iterate over the available validating IdentityStores, in priority order,
73+
until the provided Credential is validated or there are no more IdentityStores.
74+
75+
* If the Credential was validated, iterate over the available group-providing
76+
IdentityStores, in priority order, aggregating the groups returned by each store.
77+
78+
* Return the validated caller and group information.
79+
80+
An application may also supply its own `IdentityStoreHandler`, which can use any
81+
desired algorithm to select and invoke on IdentityStores, and return an
82+
aggregated (or non-aggregated) result.
83+
84+
IdentityStore Interface Details:
85+
86+
The IdentityStore interface itself has four methods:
87+
88+
* `validate(Credential)` -- validate a Credential, and return the result of that
89+
validation.
90+
91+
* `getCallerGroups(CredentialValidationResult)` -- return the groups associated
92+
with the caller indicated by the supplied `CredentialValidationResult`, which
93+
represents the result of a previous, successful validation.
94+
95+
* `validationTypes()` -- returns a Set of validation types (one or more of
96+
`VALIDATE`, `PROVIDE_GROUPS`)
97+
that indicate the operations supported by this instance of the `IdentityStore`.
98+
99+
* `priority()` -- returns a positive integer representing the self-declared
100+
priority of this IdentityStore. Lower values represent higher priority.
101+
102+
Because `getCallerGroups()` is a sensitive operation -- it can return information
103+
about arbitrary users, and does not require that the caller provide the user's
104+
credential or proof of identity -- the caller should have the
105+
`IdentityStorePermission("getGroups")` permission. Enforcement of this check is
106+
incumbent on the implementation of the `getCallerGroups()` method; the built-in
107+
IdentityStores do check for this permission, if a SecurityManager is configured,
108+
and the built-in IdentityStoreHandler invokes the `getCallerGroups()` method in
109+
the context of a `PrivilegedAction` block.
110+
111+
[[the-passwordhash-interface]]
112+
The PasswordHash Interface
113+
~~~~~~~~~~~~~~~~~~~~~~~~~~
114+
115+
Unlike some types of identity stores, for example LDAP directories,
116+
databases can store and retrieve user passwords, but can't verify them natively.
117+
Therefore, the built-in Database identity store must verify user passwords itself.
118+
Most often, this involves generating a hash of the user's password for comparison
119+
with a hash value stored in the database.
120+
121+
In order to provide maximum flexibility and interoperability, the Database identity
122+
store does not implement any specific password hashing algorithms. Instead, it
123+
defines the PasswordHash interface, and expects the application to provide an
124+
implementation of PasswordHash that can verify passwords from the specific store
125+
the application will use. The PasswordHash implementation must be made available
126+
as a dependent scoped bean, and is configured by providing the fully-qualified
127+
name of the desired type as a hashAlgorithm value on the DatabaseIdentityStoreDefinition.
128+
129+
[[the-remembermeidentitystore-interface]]
130+
The RememberMeIdentityStore Interface
131+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132+
The `RememberMeIdentityStore` interface represents a special type of identity store.
133+
It is not directly related to the `IdentityStore` interface; that is, it does not
134+
implement or extend it. It does, however, perform a similar, albeit specialized, function.
135+
136+
In some cases, an application wants to "remember" a user's authenticated session
137+
for an extended period. For example, a web site may remember you when you visit,
138+
and prompt for your password only periodically, perhaps once every two weeks,
139+
as long as you don't explicitly log out.
140+
141+
RememberMe works as follows:
142+
143+
* When a request from an unauthenicated user is received, the user is authenticated
144+
using an `HttpAuthenticationMechanism` that is provided by the application
145+
(this is required -- `RememberMeIdentityStore` can only be used in conjunction with an
146+
application-supplied `HttpAuthenticationMechanism`).
147+
148+
* After authentication, the configured `RememberMeIdentityStore` saves information
149+
about the user's authenticated identity, so that it be restored later, and
150+
generates a long-lived "remember me" login token that is sent back to the client,
151+
perhaps as a cookie.
152+
153+
* On a subsequent visit to the application, the client presents the login token.
154+
The `RememberMeIdentityStore` then validates the token and returns the stored user
155+
identity, which is then established as the user's authenticated identity.
156+
If the token is invalid or expired, it is discarded, the user is authenticated
157+
normally again, and a new login token is generated.
158+
159+
The `RememberMeIdentityStore` interface defines the following methods:
160+
161+
* `generateLoginToken(CallerPrincipal caller, Set<String> groups)` -- generate a
162+
login token for a newly authenticated user, and associate it with the provided
163+
caller/group information.
164+
165+
* `removeLoginToken(String token)` -- remove the (presumably expired or invalid)
166+
login token and any associated caller/group information.
167+
168+
* `validate(RememberMeCredential credential)` -- validate the supplied credential, and,
169+
if valid, return the associated caller/group information. (`RememberMeCredential` is
170+
essentially just a holder for a login token).
171+
172+
An implementation of `RememberMeIdentityStore` must be a CDI bean, and is assumed
173+
to be normal scoped. It is configured by adding a `RememberMe` annotation to an
174+
application's `HttpAuthenticationMechanism`, which indicates that a
175+
`RememberMeIdentityStore` is in use, and provides related configuration parameters.
176+
A container-supplied interceptor then intercepts calls to the `HttpAuthenticationMechanism`,
177+
invokes the `RememberMeIdentityStore` as necessary before and after calls to the
178+
authentication mechanism, and ensures that the user's identity is correctly
179+
set for the session. The JSR-375 specification provides a detailed description
180+
of the required interceptor behavior.
181+
182+
Implementations of `RememberMeIdentityStore` should take care to manage tokens
183+
and user identity information securely. For example, login tokens should not
184+
contain sensitive user information, like credentials or sensitive attributes,
185+
to avoid exposing that information if an attacker were able to gain access
186+
to the token -- even an encrypted token is potentially vulnerable to an
187+
attacker with sufficient time/resources. Similarly, tokens should be
188+
encrypted/signed wherever possible, and sent only over secure channels (HTTPS).
189+
User identity information managed by a `RememberMeIdentityStore` should be stored
190+
as securely as possible (but does not necessarily need to be reliably persisted --
191+
the only impact of a "forgotten" session is that the user will be prompted to
192+
log in again).
193+
194+
The PasswordHash algorithm defines three methods:
195+
196+
* `initialize(Map<String,String> parameters)` -- initialize the PasswordHash with
197+
the supplied Map of parameters. The Database identity store calls this method when
198+
initializing, passing the `hashAlgorithmParameters` value of the
199+
`DatabaseIdentityStoreDefinition` annotation (after conversion to a Map).
200+
201+
* `verify(char[] password, String hashedPassword)` -- verify a caller-supplied
202+
password against the caller's stored password hash as retrieved from the database.
203+
The `hashedPassword` value should be provided exactly as it was returned from the database.
204+
205+
* generate(char[] password) -- generate a password hash from the supplied password.
206+
The value returned should be formatted and encoded exactly it would be stored
207+
in the database. While it is useful to generate the hash of a caller-supplied password
208+
during `verify()`, this method is intended primarily for use by applications or
209+
`IdentityStore` implementations that want to support password management/reset
210+
capability without having to duplicate the code used to verify passwords.
211+
212+
Note that, while the interface is oriented toward hashing passwords, it can also
213+
support alternative approaches, such as two-way encryption of stored passwords.
214+
215+
There is a built-in `Pbkdf2PasswordHash` implementation that supports, as it's
216+
name suggests, PBKDF2 password hashing. It supports several parameters that
217+
control the generation of hash values
218+
(key size, iterations, and so on -- see the Javadoc),
219+
and those parameters are encoded into the resulting hash value, so that hashes
220+
can be verified even if the currently configured parameters are different from
221+
the parameters in effect when a stored hash was generated.
222+
223+
While it is necessary to write a custom `PasswordHash` to enable interoperability
224+
with a legacy identity store that stores password hashes in a format other
225+
than the `Pbkdf2PasswordHash` format, developers should consider carefully
226+
whether `Pbkdf2PasswordHash` is sufficient for new identity stores, and avoid
227+
writing a new PasswordHash implementation without a solid understanding of the
228+
cryptographic and other security considerations involved. Some of the
229+
considerations specific to password hashing are:
230+
231+
* The requirements for hashing passwords differ considerably from the requirements
232+
for hashing in other contexts. In particular, speed is normally a virtue when
233+
generating hashes, but when generating password hashes, slower is better -- to
234+
slow down brute force attacks against hashed values.
235+
236+
* The comparison of a generated hash with a stored hash should take constant time,
237+
whether it succeeds or fails, in order to avoid giving an attacker clues about
238+
the password value based on the timing of failed attempts.
239+
240+
* A new random salt should be used each time a new password hash value is generated.

src/main/jbake/content/security-api004.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ Map the DatabaseIdentityStore to the Default Data source
141141
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
142142
Use the `@DatabaseIdentityStoreDefinition` annotation to map the built-in `DatabaseIdentityStore`
143143
to the `DefaultDataSource` in
144-
the `ApplicationConfig.java` file.
144+
the `ApplicationConfig.java` file. This example also demonstrates the use of the
145+
`Pbkdf2PasswordHash` interface.
145146

146147
[source,oac_no_warn]
147148
----

0 commit comments

Comments
 (0)