Skip to content

Commit 338b637

Browse files
committed
Document Mock Jwt Testing
Fixes gh-7242
1 parent bdaf530 commit 338b637

File tree

1 file changed

+119
-0
lines changed
  • docs/manual/src/docs/asciidoc/_includes/servlet/test

1 file changed

+119
-0
lines changed

docs/manual/src/docs/asciidoc/_includes/servlet/test/mockmvc.adoc

+119
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,125 @@ mvc
280280
.perform(formLogin("/auth").user("u","admin").password("p","pass"))
281281
----
282282

283+
284+
==== Testing Bearer Authentication
285+
286+
In order to make an authorized request on a resource server, you need a bearer token.
287+
If your resource server is configured for JWTs, then this would mean that the bearer token needs to be signed and then encoded according to the JWT specification.
288+
All of this can be quite daunting, especially when this isn't the focus of your test.
289+
290+
Fortunately, there are a number of simple ways that you can overcome this difficulty and allow your tests to focus on authorization and not on representing bearer tokens.
291+
We'll look at two of them now:
292+
293+
===== `jwt() RequestPostProcessor`
294+
295+
The first way is via a `RequestPostProcessor`.
296+
The simplest of these would look something like this:
297+
298+
[source,java]
299+
----
300+
mvc
301+
.perform(get("/endpoint").with(jwt()));
302+
----
303+
304+
What this will do is create a mock `Jwt`, passing it correctly through any authentication APIs so that it's available for your authorization mechanisms to verify.
305+
306+
By default, the `JWT` that it creates has the following characteristics:
307+
308+
[source,json]
309+
----
310+
{
311+
"headers" : { "alg" : "none" },
312+
"claims" : {
313+
"sub" : "user",
314+
"scope" : "read"
315+
}
316+
}
317+
----
318+
319+
And the resulting `Jwt`, were it tested, would pass in the following way:
320+
321+
[source,java]
322+
----
323+
assertThat(jwt.getTokenValue()).isEqualTo("token");
324+
assertThat(jwt.getHeaders().get("alg")).isEqualTo("none");
325+
assertThat(jwt.getSubject()).isEqualTo("sub");
326+
GrantedAuthority authority = jwt.getAuthorities().iterator().next();
327+
assertThat(authority.getAuthority()).isEqualTo("read");
328+
----
329+
330+
These values can, of course be configured.
331+
332+
Any headers or claims can be configured with their corresponding methods:
333+
334+
[source,java]
335+
----
336+
mvc
337+
.perform(get("/endpoint")
338+
.with(jwt(jwt -> jwt.header("kid", "one").claim("iss", "https://idp.example.org"))));
339+
----
340+
341+
[source,java]
342+
----
343+
mvc
344+
.perform(get("/endpoint")
345+
.with(jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))));
346+
----
347+
348+
The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request.
349+
However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test:
350+
351+
[source,java]
352+
----
353+
mvc
354+
.perform(get("/endpoint")
355+
.with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages"))));
356+
----
357+
358+
Or, if you have a custom `Jwt` to `Collection<GrantedAuthority>` converter, you can also use that to derive the authorities:
359+
360+
[source,java]
361+
----
362+
mvc
363+
.perform(get("/endpoint")
364+
.with(jwt().authorities(new MyConverter())));
365+
----
366+
367+
You can also specify a complete `Jwt`, for which `Jwt.Builder` comes quite handy:
368+
369+
[source,java]
370+
----
371+
Jwt jwt = Jwt.withTokenValue("token")
372+
.header("alg", "none")
373+
.claim("sub", "user")
374+
.claim("scope", "read");
375+
376+
mvc
377+
.perform(get("/endpoint")
378+
.with(jwt(jwt)));
379+
----
380+
381+
===== `authentication()` `RequestPostProcessor`
382+
383+
The second way is by using the `authentication()` `RequestPostProcessor`.
384+
Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so:
385+
386+
[source,java]
387+
----
388+
Jwt jwt = Jwt.withTokenValue("token")
389+
.header("alg", "none")
390+
.claim("sub", "user")
391+
.build();
392+
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("SCOPE_read");
393+
JwtAuthenticationToken token = new JwtAuthenticationToken(jwt, authorities);
394+
395+
mvc
396+
.perform(get("/endpoint")
397+
.with(authentication(token)));
398+
----
399+
400+
Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation.
401+
283402
[[test-logout]]
284403
==== Testing Logout
285404

0 commit comments

Comments
 (0)