parent
bdaf530511
commit
338b637ab5
|
@ -280,6 +280,125 @@ mvc
|
||||||
.perform(formLogin("/auth").user("u","admin").password("p","pass"))
|
.perform(formLogin("/auth").user("u","admin").password("p","pass"))
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
==== Testing Bearer Authentication
|
||||||
|
|
||||||
|
In order to make an authorized request on a resource server, you need a bearer token.
|
||||||
|
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.
|
||||||
|
All of this can be quite daunting, especially when this isn't the focus of your test.
|
||||||
|
|
||||||
|
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.
|
||||||
|
We'll look at two of them now:
|
||||||
|
|
||||||
|
===== `jwt() RequestPostProcessor`
|
||||||
|
|
||||||
|
The first way is via a `RequestPostProcessor`.
|
||||||
|
The simplest of these would look something like this:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint").with(jwt()));
|
||||||
|
----
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
By default, the `JWT` that it creates has the following characteristics:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"headers" : { "alg" : "none" },
|
||||||
|
"claims" : {
|
||||||
|
"sub" : "user",
|
||||||
|
"scope" : "read"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
And the resulting `Jwt`, were it tested, would pass in the following way:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
assertThat(jwt.getTokenValue()).isEqualTo("token");
|
||||||
|
assertThat(jwt.getHeaders().get("alg")).isEqualTo("none");
|
||||||
|
assertThat(jwt.getSubject()).isEqualTo("sub");
|
||||||
|
GrantedAuthority authority = jwt.getAuthorities().iterator().next();
|
||||||
|
assertThat(authority.getAuthority()).isEqualTo("read");
|
||||||
|
----
|
||||||
|
|
||||||
|
These values can, of course be configured.
|
||||||
|
|
||||||
|
Any headers or claims can be configured with their corresponding methods:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(jwt(jwt -> jwt.header("kid", "one").claim("iss", "https://idp.example.org"))));
|
||||||
|
----
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(jwt(jwt -> jwt.claims(claims -> claims.remove("scope")))));
|
||||||
|
----
|
||||||
|
|
||||||
|
The `scope` and `scp` claims are processed the same way here as they are in a normal bearer token request.
|
||||||
|
However, this can be overridden simply by providing the list of `GrantedAuthority` instances that you need for your test:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_messages"))));
|
||||||
|
----
|
||||||
|
|
||||||
|
Or, if you have a custom `Jwt` to `Collection<GrantedAuthority>` converter, you can also use that to derive the authorities:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(jwt().authorities(new MyConverter())));
|
||||||
|
----
|
||||||
|
|
||||||
|
You can also specify a complete `Jwt`, for which `Jwt.Builder` comes quite handy:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
Jwt jwt = Jwt.withTokenValue("token")
|
||||||
|
.header("alg", "none")
|
||||||
|
.claim("sub", "user")
|
||||||
|
.claim("scope", "read");
|
||||||
|
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(jwt(jwt)));
|
||||||
|
----
|
||||||
|
|
||||||
|
===== `authentication()` `RequestPostProcessor`
|
||||||
|
|
||||||
|
The second way is by using the `authentication()` `RequestPostProcessor`.
|
||||||
|
Essentially, you can instantiate your own `JwtAuthenticationToken` and provide it in your test, like so:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
Jwt jwt = Jwt.withTokenValue("token")
|
||||||
|
.header("alg", "none")
|
||||||
|
.claim("sub", "user")
|
||||||
|
.build();
|
||||||
|
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("SCOPE_read");
|
||||||
|
JwtAuthenticationToken token = new JwtAuthenticationToken(jwt, authorities);
|
||||||
|
|
||||||
|
mvc
|
||||||
|
.perform(get("/endpoint")
|
||||||
|
.with(authentication(token)));
|
||||||
|
----
|
||||||
|
|
||||||
|
Note that as an alternative to these, you can also mock the `JwtDecoder` bean itself with a `@MockBean` annotation.
|
||||||
|
|
||||||
[[test-logout]]
|
[[test-logout]]
|
||||||
==== Testing Logout
|
==== Testing Logout
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue