diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoder.java index 3ec9e37511..7a16daf188 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoder.java @@ -119,8 +119,9 @@ public final class NimbusJwkReactiveJwtDecoder implements ReactiveJwtDecoder { .createSelector(parsedToken.getHeader()); return this.reactiveJwkSource.get(selector) .map(jwkList -> createJwkSet(parsedToken, jwkList)) - .map(set -> createJwt(parsedToken, set)); - } catch (Exception ex) { + .map(set -> createJwt(parsedToken, set)) + .onErrorMap(e -> new JwtException("An error occurred while attempting to decode the Jwt: ", e)); + } catch (RuntimeException ex) { throw new JwtException("An error occurred while attempting to decode the Jwt: " + ex.getMessage(), ex); } } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoderTests.java index 981ad356ae..ef38f1917f 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwkReactiveJwtDecoderTests.java @@ -16,26 +16,16 @@ package org.springframework.security.oauth2.jwt; -import com.nimbusds.jose.jwk.JWK; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.RSAKey; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.springframework.security.crypto.keygen.KeyGenerators; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Base64; -import java.util.Map; +import java.util.Date; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; /** * @author Rob Winch @@ -43,11 +33,12 @@ import static org.assertj.core.api.Assertions.*; */ public class NimbusJwkReactiveJwtDecoderTests { - String expired = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6Im1lc3NhZ2U6cmVhZCIsImV4cCI6MTUyOTkzNzYzMX0.Dt5jFOKkB8zAmjciwvlGkj4LNStXWH0HNIfr8YYajIthBIpVgY5Hg_JL8GBmUFzKDgyusT0q60OOg8_Pdi4Lu-VTWyYutLSlNUNayMlyBaVEWfyZJnh2_OwMZr1vRys6HF-o1qZldhwcfvczHg61LwPa1ISoqaAltDTzBu9cGISz2iBUCuR0x71QhbuRNyJdjsyS96NqiM_TspyiOSxmlNch2oAef1MssOQ23CrKilIvEDsz_zk5H94q7rH0giWGdEHCENESsTJS0zvzH6r2xIWjd5WnihFpCPkwznEayxaEhrdvJqT_ceyXCIfY4m3vujPQHNDG0UshpwvDuEbPUg"; - String messageReadToken = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6Im1lc3NhZ2U6cmVhZCIsImV4cCI6OTIyMzM3MjAwNjA5NjM3NX0.bnQ8IJDXmQbmIXWku0YT1HOyV_3d0iQSA_0W2CmPyELhsxFETzBEEcZ0v0xCBiswDT51rwD83wbX3YXxb84fM64AhpU8wWOxLjha4J6HJX2JnlG47ydaAVD7eWGSYTavyyQ-CwUjQWrfMVcObFZLYG11ydzRYOR9-aiHcK3AobcTcS8jZFeI8EGQV_Cd3IJ018uFCf6VnXLv7eV2kRt08Go2RiPLW47ExvD7Dzzz_wDBKfb4pNem7fDvuzB3UPcp5m9QvLZicnbS_6AvDi6P1y_DFJf-1T5gkGmX5piDH1L1jg2Yl6tjmXbk5B3VhsyjJuXE6gzq1d-xie0Z1NVOxw"; - String noScopes = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6IiIsImV4cCI6OTIyMzM3MjAwNjA5NjM3NX0.asF3shV-lLdM4WmsnKd2xjqXu-VJuJjPT-ywkj56lUe4suQDy2tPtkzur7a0uVKj2VDoobzFHOW80F_-67E2aXOJSKBCk9qnqu8GyRiMKdmVekIacEl9EYdZAo6XBvuUJCmcTPNTkJIJifNSQmu33GqJeEw_oJA1CEyg5spIOy_TYCBdQ-jRmuzA5WpdRBmQlr4T-36rccimXwtBLgxK9e7FmUMlP51mkq7UdlOELF6wFn6bh3L4YJbfiKfK-rZAPZjwjio3fr24YTQM4MrqSVTSA5Z0gjHxsz_oTPmrrOzXVY8KVTfkw2OzYuNsPbtlnLJn64cgO2h6AfIc672Aaw"; + private String expired = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6Im1lc3NhZ2U6cmVhZCIsImV4cCI6MTUyOTkzNzYzMX0.Dt5jFOKkB8zAmjciwvlGkj4LNStXWH0HNIfr8YYajIthBIpVgY5Hg_JL8GBmUFzKDgyusT0q60OOg8_Pdi4Lu-VTWyYutLSlNUNayMlyBaVEWfyZJnh2_OwMZr1vRys6HF-o1qZldhwcfvczHg61LwPa1ISoqaAltDTzBu9cGISz2iBUCuR0x71QhbuRNyJdjsyS96NqiM_TspyiOSxmlNch2oAef1MssOQ23CrKilIvEDsz_zk5H94q7rH0giWGdEHCENESsTJS0zvzH6r2xIWjd5WnihFpCPkwznEayxaEhrdvJqT_ceyXCIfY4m3vujPQHNDG0UshpwvDuEbPUg"; + + private String messageReadToken = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6Im1lc3NhZ2U6cmVhZCIsImV4cCI6OTIyMzM3MjAwNjA5NjM3NX0.bnQ8IJDXmQbmIXWku0YT1HOyV_3d0iQSA_0W2CmPyELhsxFETzBEEcZ0v0xCBiswDT51rwD83wbX3YXxb84fM64AhpU8wWOxLjha4J6HJX2JnlG47ydaAVD7eWGSYTavyyQ-CwUjQWrfMVcObFZLYG11ydzRYOR9-aiHcK3AobcTcS8jZFeI8EGQV_Cd3IJ018uFCf6VnXLv7eV2kRt08Go2RiPLW47ExvD7Dzzz_wDBKfb4pNem7fDvuzB3UPcp5m9QvLZicnbS_6AvDi6P1y_DFJf-1T5gkGmX5piDH1L1jg2Yl6tjmXbk5B3VhsyjJuXE6gzq1d-xie0Z1NVOxw"; + private String jwkSet = - "{\n" + "{\n" + " \"keys\":[\n" + " {\n" + " \"kty\":\"RSA\",\n" @@ -77,19 +68,39 @@ public class NimbusJwkReactiveJwtDecoderTests { @Test public void decodeWhenMessageReadScopeThenSuccess() { - NimbusJwkReactiveJwtDecoder decoder = new NimbusJwkReactiveJwtDecoder(this.server.url("/certs").toString()); - - Jwt jwt = decoder.decode(this.messageReadToken).block(); + Jwt jwt = this.decoder.decode(this.messageReadToken).block(); assertThat(jwt.getClaims().get("scope")).isEqualTo("message:read"); } + @Test + public void decodeWhenIssuedAtThenSuccess() { + String withIssuedAt = "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2In0.eyJzY29wZSI6IiIsImV4cCI6OTIyMzM3MjAwNjA5NjM3NSwiaWF0IjoxNTI5OTQyNDQ4fQ.LBzAJO-FR-uJDHST61oX4kimuQjz6QMJPW_mvEXRB6A-fMQWpfTQ089eboipAqsb33XnwWth9ELju9HMWLk0FjlWVVzwObh9FcoKelmPNR8mZIlFG-pAYGgSwi8HufyLabXHntFavBiFtqwp_z9clSOFK1RxWvt3lywEbGgtCKve0BXOjfKWiH1qe4QKGixH-NFxidvz8Qd5WbJwyb9tChC6ZKoKPv7Jp-N5KpxkY-O2iUtINvn4xOSactUsvKHgF8ZzZjvJGzG57r606OZXaNtoElQzjAPU5xDGg5liuEJzfBhvqiWCLRmSuZ33qwp3aoBnFgEw0B85gsNe3ggABg"; + + Jwt jwt = this.decoder.decode(withIssuedAt).block(); + + assertThat(jwt.getClaims().get(JwtClaimNames.IAT)).isEqualTo(new Date(1529942448000L)); + } + @Test public void decodeWhenExpiredThenFail() { assertThatCode(() -> this.decoder.decode(this.expired).block()) .isInstanceOf(JwtException.class); } + @Test + public void decodeWhenNoPeriodThenFail() { + assertThatCode(() -> this.decoder.decode("").block()) + .isInstanceOf(JwtException.class); + } + + @Test + public void decodeWhenInvalidJwkSetUrlThenFail() { + this.decoder = new NimbusJwkReactiveJwtDecoder("http://localhost:1280/certs"); + assertThatCode(() -> this.decoder.decode(this.messageReadToken).block()) + .isInstanceOf(JwtException.class); + } + @Test public void decodeWhenInvalidSignatureThenFail() { assertThatCode(() -> this.decoder.decode(this.messageReadToken.substring(0, this.messageReadToken.length() - 2)).block()) @@ -102,4 +113,10 @@ public class NimbusJwkReactiveJwtDecoderTests { .isInstanceOf(JwtException.class) .hasMessage("Unsupported algorithm of none"); } + + @Test + public void decodeWhenInvalidAlgMismatchThenFail() { + assertThatCode(() -> this.decoder.decode("ew0KICAiYWxnIjogIkVTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJKb2huIERvZSIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.").block()) + .isInstanceOf(JwtException.class); + } }