From 224a3b6472ba01bcec58c8dd4e9f44f14df5cc1f Mon Sep 17 00:00:00 2001 From: Ulrich Grave Date: Fri, 29 Apr 2022 08:21:21 +0200 Subject: [PATCH] Add Jackson Support for Saml2AuthenticationException Closes gh-11169 --- .../Saml2AuthenticationExceptionMixin.java | 47 ++++++++++++++ .../saml2/jackson2/Saml2ErrorMixin.java | 45 ++++++++++++++ .../saml2/jackson2/Saml2Jackson2Module.java | 9 ++- ...Saml2AuthenticationExceptionMixinTest.java | 61 +++++++++++++++++++ .../saml2/jackson2/TestSaml2JsonPayloads.java | 18 ++++++ 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixin.java create mode 100644 saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2ErrorMixin.java create mode 100644 saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixinTest.java diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixin.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixin.java new file mode 100644 index 00000000000..3bbee42f240 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixin.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.jackson2; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; + +/** + * This mixin class is used to serialize/deserialize {@link Saml2AuthenticationException}. + * + * @author Ulrich Grave + * @since 5.7 + * @see Saml2AuthenticationException + * @see Saml2Jackson2Module + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE) +@JsonIgnoreProperties(ignoreUnknown = true, value = { "cause", "stackTrace", "suppressedExceptions" }) +class Saml2AuthenticationExceptionMixin { + + @JsonCreator + Saml2AuthenticationExceptionMixin(@JsonProperty("error") Saml2Error error, + @JsonProperty("detailMessage") String message) { + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2ErrorMixin.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2ErrorMixin.java new file mode 100644 index 00000000000..b4af0e70612 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2ErrorMixin.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.jackson2; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import org.springframework.security.saml2.core.Saml2Error; + +/** + * This mixin class is used to serialize/deserialize {@link Saml2Error}. + * + * @author Ulrich Grave + * @since 5.7 + * @see Saml2Error + * @see Saml2Jackson2Module + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + isGetterVisibility = JsonAutoDetect.Visibility.NONE) +@JsonIgnoreProperties(ignoreUnknown = true) +class Saml2ErrorMixin { + + @JsonCreator + Saml2ErrorMixin(@JsonProperty("errorCode") String errorCode, @JsonProperty("description") String description) { + } + +} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java index 0febccb6267..025ffc6b36b 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/jackson2/Saml2Jackson2Module.java @@ -20,8 +20,10 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; @@ -29,8 +31,9 @@ /** * Jackson module for saml2-service-provider. This module register * {@link Saml2AuthenticationMixin}, {@link DefaultSaml2AuthenticatedPrincipalMixin}, - * {@link Saml2LogoutRequestMixin}, {@link Saml2RedirectAuthenticationRequestMixin} and - * {@link Saml2PostAuthenticationRequestMixin}. + * {@link Saml2LogoutRequestMixin}, {@link Saml2RedirectAuthenticationRequestMixin}, + * {@link Saml2PostAuthenticationRequestMixin}, {@link Saml2ErrorMixin} and + * {@link Saml2AuthenticationExceptionMixin}. * * @author Ulrich Grave * @since 5.7 @@ -51,6 +54,8 @@ public void setupModule(SetupContext context) { context.setMixInAnnotations(Saml2RedirectAuthenticationRequest.class, Saml2RedirectAuthenticationRequestMixin.class); context.setMixInAnnotations(Saml2PostAuthenticationRequest.class, Saml2PostAuthenticationRequestMixin.class); + context.setMixInAnnotations(Saml2Error.class, Saml2ErrorMixin.class); + context.setMixInAnnotations(Saml2AuthenticationException.class, Saml2AuthenticationExceptionMixin.class); } } diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixinTest.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixinTest.java new file mode 100644 index 00000000000..b6c2b22711c --- /dev/null +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/Saml2AuthenticationExceptionMixinTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2.jackson2; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; + +import org.springframework.security.jackson2.SecurityJackson2Modules; +import org.springframework.security.saml2.core.Saml2Error; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; + +import static org.assertj.core.api.Assertions.assertThat; + +class Saml2AuthenticationExceptionMixinTest { + + private ObjectMapper mapper; + + @BeforeEach + void setUp() { + this.mapper = new ObjectMapper(); + ClassLoader loader = getClass().getClassLoader(); + this.mapper.registerModules(SecurityJackson2Modules.getModules(loader)); + } + + @Test + void shouldSerialize() throws Exception { + Saml2AuthenticationException exception = TestSaml2JsonPayloads.createDefaultSaml2AuthenticationException(); + + String exceptionJson = this.mapper.writeValueAsString(exception); + + JSONAssert.assertEquals(TestSaml2JsonPayloads.DEFAULT_SAML_AUTH_EXCEPTION_JSON, exceptionJson, true); + } + + @Test + void shouldDeserialize() throws Exception { + Saml2AuthenticationException exception = this.mapper + .readValue(TestSaml2JsonPayloads.DEFAULT_SAML_AUTH_EXCEPTION_JSON, Saml2AuthenticationException.class); + + assertThat(exception).isNotNull(); + assertThat(exception.getMessage()).isEqualTo("exceptionMessage"); + assertThat(exception.getSaml2Error()).extracting(Saml2Error::getErrorCode, Saml2Error::getDescription) + .contains("errorCode", "errorDescription"); + } + +} diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/TestSaml2JsonPayloads.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/TestSaml2JsonPayloads.java index d0dd0deafe6..ed3e36ec3ed 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/TestSaml2JsonPayloads.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/jackson2/TestSaml2JsonPayloads.java @@ -26,8 +26,10 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; +import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; @@ -216,4 +218,20 @@ static Saml2Authentication createDefaultAuthentication() { return authentication; } + // @formatter:off + static final String DEFAULT_SAML_AUTH_EXCEPTION_JSON = "{" + + " \"@class\": \"org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException\"," + + " \"detailMessage\": \"exceptionMessage\"," + + " \"error\": {" + + " \"@class\": \"org.springframework.security.saml2.core.Saml2Error\"," + + " \"errorCode\": \"errorCode\"," + + " \"description\": \"errorDescription\"" + + " }" + + "}"; + // @formatter:on + + static Saml2AuthenticationException createDefaultSaml2AuthenticationException() { + return new Saml2AuthenticationException(new Saml2Error("errorCode", "errorDescription"), "exceptionMessage"); + } + }