11/*
2- * Copyright 2002-2021 the original author or authors.
2+ * Copyright 2002-2025 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
2323import java .util .Collections ;
2424import java .util .List ;
2525
26+ import com .nimbusds .jose .JWSAlgorithm ;
2627import com .nimbusds .jose .KeySourceException ;
2728import com .nimbusds .jose .jwk .ECKey ;
2829import com .nimbusds .jose .jwk .JWK ;
3940import org .mockito .invocation .InvocationOnMock ;
4041import org .mockito .stubbing .Answer ;
4142
43+ import org .springframework .core .convert .converter .Converter ;
4244import org .springframework .security .oauth2 .jose .TestJwks ;
4345import org .springframework .security .oauth2 .jose .TestKeys ;
4446import org .springframework .security .oauth2 .jose .jws .SignatureAlgorithm ;
5153import static org .mockito .BDDMockito .willAnswer ;
5254import static org .mockito .Mockito .mock ;
5355import static org .mockito .Mockito .spy ;
56+ import static org .mockito .Mockito .verify ;
57+ import static org .mockito .Mockito .verifyNoInteractions ;
5458
5559/**
5660 * Tests for {@link NimbusJwtEncoder}.
@@ -109,7 +113,7 @@ public void encodeWhenJwkSelectFailedThenThrowJwtEncodingException() throws Exce
109113
110114 @ Test
111115 public void encodeWhenJwkMultipleSelectedThenThrowJwtEncodingException () throws Exception {
112- RSAKey rsaJwk = TestJwks .DEFAULT_RSA_JWK ;
116+ RSAKey rsaJwk = TestJwks .rsa (). algorithm ( JWSAlgorithm . RS256 ). build () ;
113117 this .jwkList .add (rsaJwk );
114118 this .jwkList .add (rsaJwk );
115119
@@ -118,7 +122,7 @@ public void encodeWhenJwkMultipleSelectedThenThrowJwtEncodingException() throws
118122
119123 assertThatExceptionOfType (JwtEncodingException .class )
120124 .isThrownBy (() -> this .jwtEncoder .encode (JwtEncoderParameters .from (jwsHeader , jwtClaimsSet )))
121- .withMessageContaining ("Found multiple JWK signing keys for algorithm ' RS256' " );
125+ .withMessageContaining ("Failed to select a key since there are multiple for the signing algorithm [ RS256] " );
122126 }
123127
124128 @ Test
@@ -291,6 +295,55 @@ public List<JWK> get(JWKSelector jwkSelector, SecurityContext context) {
291295 assertThat (jwk1 .getKeyID ()).isNotEqualTo (jwk2 .getKeyID ());
292296 }
293297
298+ @ Test
299+ public void encodeWhenMultipleKeysThenJwkSelectorUsed () throws Exception {
300+ JWK jwk = TestJwks .rsa ().algorithm (JWSAlgorithm .RS256 ).build ();
301+ JWKSource <SecurityContext > jwkSource = mock (JWKSource .class );
302+ given (jwkSource .get (any (), any ())).willReturn (List .of (jwk , jwk ));
303+ Converter <List <JWK >, JWK > selector = mock (Converter .class );
304+ given (selector .convert (any ())).willReturn (TestJwks .DEFAULT_RSA_JWK );
305+
306+ NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder (jwkSource );
307+ jwtEncoder .setJwkSelector (selector );
308+
309+ JwtClaimsSet claims = JwtClaimsSet .builder ().subject ("sub" ).build ();
310+ jwtEncoder .encode (JwtEncoderParameters .from (claims ));
311+
312+ verify (selector ).convert (any ());
313+ }
314+
315+ @ Test
316+ public void encodeWhenSingleKeyThenJwkSelectorIsNotUsed () throws Exception {
317+ JWK jwk = TestJwks .rsa ().algorithm (JWSAlgorithm .RS256 ).build ();
318+ JWKSource <SecurityContext > jwkSource = mock (JWKSource .class );
319+ given (jwkSource .get (any (), any ())).willReturn (List .of (jwk ));
320+ Converter <List <JWK >, JWK > selector = mock (Converter .class );
321+
322+ NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder (jwkSource );
323+ jwtEncoder .setJwkSelector (selector );
324+
325+ JwtClaimsSet claims = JwtClaimsSet .builder ().subject ("sub" ).build ();
326+ jwtEncoder .encode (JwtEncoderParameters .from (claims ));
327+
328+ verifyNoInteractions (selector );
329+ }
330+
331+ @ Test
332+ public void encodeWhenNoKeysThenJwkSelectorIsNotUsed () throws Exception {
333+ JWKSource <SecurityContext > jwkSource = mock (JWKSource .class );
334+ given (jwkSource .get (any (), any ())).willReturn (List .of ());
335+ Converter <List <JWK >, JWK > selector = mock (Converter .class );
336+
337+ NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder (jwkSource );
338+ jwtEncoder .setJwkSelector (selector );
339+
340+ JwtClaimsSet claims = JwtClaimsSet .builder ().subject ("sub" ).build ();
341+ assertThatExceptionOfType (JwtEncodingException .class )
342+ .isThrownBy (() -> jwtEncoder .encode (JwtEncoderParameters .from (claims )));
343+
344+ verifyNoInteractions (selector );
345+ }
346+
294347 private static final class JwkListResultCaptor implements Answer <List <JWK >> {
295348
296349 private List <JWK > result ;
0 commit comments