Skip to content

Commit 8254f58

Browse files
marcusdacoregiojzheaux
authored andcommitted
Create Jackson Mixin for OneTimeTokenAuthentication
Closes gh-18095 Signed-off-by: Marcus Hert da Coregio <marcusdacoregio@gmail.com>
1 parent 92b7c41 commit 8254f58

6 files changed

Lines changed: 179 additions & 0 deletions

File tree

core/src/main/java/org/springframework/security/jackson/CoreJacksonModule.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.security.authentication.RememberMeAuthenticationToken;
3030
import org.springframework.security.authentication.TestingAuthenticationToken;
3131
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
32+
import org.springframework.security.authentication.ott.OneTimeTokenAuthentication;
3233
import org.springframework.security.core.authority.FactorGrantedAuthority;
3334
import org.springframework.security.core.authority.SimpleGrantedAuthority;
3435
import org.springframework.security.core.context.SecurityContextImpl;
@@ -81,6 +82,7 @@ public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Buil
8182
.allowIfSubType(BadCredentialsException.class)
8283
.allowIfSubType(SecurityContextImpl.class)
8384
.allowIfSubType(TestingAuthenticationToken.class)
85+
.allowIfSubType(OneTimeTokenAuthentication.class)
8486
.allowIfSubType("java.util.Collections$UnmodifiableSet")
8587
.allowIfSubType("java.util.Collections$UnmodifiableRandomAccessList")
8688
.allowIfSubType("java.util.Collections$EmptyList")
@@ -108,6 +110,7 @@ public void setupModule(SetupContext context) {
108110
context.setMixIn(UsernamePasswordAuthenticationToken.class, UsernamePasswordAuthenticationTokenMixin.class);
109111
context.setMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class);
110112
context.setMixIn(BadCredentialsException.class, BadCredentialsExceptionMixin.class);
113+
context.setMixIn(OneTimeTokenAuthentication.class, OneTimeTokenAuthenticationMixin.class);
111114
}
112115

113116
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.jackson;
18+
19+
import java.util.Collection;
20+
21+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
22+
import com.fasterxml.jackson.annotation.JsonCreator;
23+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
24+
import com.fasterxml.jackson.annotation.JsonProperty;
25+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
26+
27+
import org.springframework.security.core.GrantedAuthority;
28+
29+
/**
30+
* Jackson Mixin class helps in serialize/deserialize
31+
* {@link org.springframework.security.authentication.ott.OneTimeTokenAuthentication}.
32+
*
33+
* <pre>
34+
* JsonMapper mapper = JsonMapper.builder()
35+
* .addModules(new CoreJacksonModule())
36+
* .build();
37+
* </pre>
38+
*
39+
* @author Marcus Da Coregio
40+
* @since 7.1
41+
* @see CoreJacksonModule
42+
* @see SecurityJacksonModules
43+
*
44+
*/
45+
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
46+
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
47+
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
48+
@JsonIgnoreProperties(ignoreUnknown = true)
49+
abstract class OneTimeTokenAuthenticationMixin {
50+
51+
@JsonCreator
52+
OneTimeTokenAuthenticationMixin(@JsonProperty("principal") Object principal,
53+
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities) {
54+
}
55+
56+
}

core/src/main/java/org/springframework/security/jackson2/CoreJackson2Module.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.security.authentication.BadCredentialsException;
2626
import org.springframework.security.authentication.RememberMeAuthenticationToken;
2727
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
28+
import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken;
2829
import org.springframework.security.core.authority.FactorGrantedAuthority;
2930
import org.springframework.security.core.authority.SimpleGrantedAuthority;
3031
import org.springframework.security.core.userdetails.User;
@@ -75,6 +76,7 @@ public void setupModule(SetupContext context) {
7576
context.setMixInAnnotations(UsernamePasswordAuthenticationToken.class,
7677
UsernamePasswordAuthenticationTokenMixin.class);
7778
context.setMixInAnnotations(BadCredentialsException.class, BadCredentialsExceptionMixin.class);
79+
context.setMixInAnnotations(OneTimeTokenAuthenticationToken.class, OneTimeTokenAuthenticationTokenMixin.class);
7880
}
7981

8082
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.jackson2;
18+
19+
import java.util.Collection;
20+
21+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
22+
import com.fasterxml.jackson.annotation.JsonCreator;
23+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
24+
import com.fasterxml.jackson.annotation.JsonProperty;
25+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
26+
27+
import org.springframework.security.core.GrantedAuthority;
28+
29+
/**
30+
* Jackson Mixin class helps in serialize/deserialize
31+
* {@link org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken}.
32+
*
33+
* <pre>
34+
* ObjectMapper mapper = new ObjectMapper();
35+
* mapper.registerModule(new CoreJackson2Module());
36+
* </pre>
37+
*
38+
* @author Marcus Da Coregio
39+
* @since 7.1
40+
* @see CoreJackson2Module
41+
* @see SecurityJackson2Modules
42+
*
43+
*/
44+
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
45+
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
46+
getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
47+
@JsonIgnoreProperties(ignoreUnknown = true)
48+
abstract class OneTimeTokenAuthenticationTokenMixin {
49+
50+
@JsonCreator
51+
OneTimeTokenAuthenticationTokenMixin(@JsonProperty("principal") Object principal,
52+
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities) {
53+
}
54+
55+
}

core/src/test/java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
import java.util.Set;
2020

2121
import org.junit.jupiter.api.Test;
22+
import tools.jackson.databind.json.JsonMapper;
2223

24+
import org.springframework.security.core.GrantedAuthority;
2325
import org.springframework.security.core.authority.AuthorityUtils;
26+
import org.springframework.security.jackson.SecurityJacksonModules;
2427

2528
import static org.assertj.core.api.Assertions.assertThat;
2629

@@ -41,4 +44,18 @@ void toBuilderWhenApplyThenCopies() {
4144
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
4245
}
4346

47+
// gh-18095
48+
@Test
49+
void shouldBeAbleToDeserializeFromJsonWithDefaultTypingActivated() {
50+
JsonMapper mapper = JsonMapper.builder()
51+
.addModules(SecurityJacksonModules.getModules(getClass().getClassLoader()))
52+
.build();
53+
OneTimeTokenAuthentication oneTimeTokenAuthentication = new OneTimeTokenAuthentication("principal",
54+
AuthorityUtils.createAuthorityList("ROLE_USER"));
55+
byte[] serialized = mapper.writeValueAsBytes(oneTimeTokenAuthentication);
56+
OneTimeTokenAuthentication deserialized = mapper.readValue(serialized, OneTimeTokenAuthentication.class);
57+
assertThat(deserialized.getPrincipal()).isEqualTo(oneTimeTokenAuthentication.getPrincipal());
58+
assertThat(deserialized.getAuthorities()).extracting(GrantedAuthority::getAuthority).contains("ROLE_USER");
59+
}
60+
4461
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authentication.ott;
18+
19+
import java.io.IOException;
20+
21+
import com.fasterxml.jackson.databind.ObjectMapper;
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.security.core.GrantedAuthority;
25+
import org.springframework.security.core.authority.AuthorityUtils;
26+
import org.springframework.security.jackson2.SecurityJackson2Modules;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
class OneTimeTokenAuthenticationTokenTests {
31+
32+
// gh-18095
33+
@Test
34+
void shouldBeAbleToDeserializeFromJsonWithDefaultTypingActivated() throws IOException {
35+
ObjectMapper mapper = new ObjectMapper();
36+
mapper.registerModules(SecurityJackson2Modules.getModules(getClass().getClassLoader()));
37+
OneTimeTokenAuthenticationToken oneTimeTokenAuthenticationToken = new OneTimeTokenAuthenticationToken(
38+
"principal", AuthorityUtils.createAuthorityList("ROLE_USER"));
39+
byte[] serialized = mapper.writeValueAsBytes(oneTimeTokenAuthenticationToken);
40+
OneTimeTokenAuthenticationToken deserialized = mapper.readValue(serialized,
41+
OneTimeTokenAuthenticationToken.class);
42+
assertThat(deserialized.getPrincipal()).isEqualTo(oneTimeTokenAuthenticationToken.getPrincipal());
43+
assertThat(deserialized.getAuthorities()).extracting(GrantedAuthority::getAuthority).contains("ROLE_USER");
44+
}
45+
46+
}

0 commit comments

Comments
 (0)