parent
7cfd415cb5
commit
4f8c1b34af
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -209,6 +209,7 @@ public final class SecurityJackson2Modules {
|
|||
names.add("java.util.HashMap");
|
||||
names.add("java.util.LinkedHashMap");
|
||||
names.add("org.springframework.security.core.context.SecurityContextImpl");
|
||||
names.add("java.util.Arrays$ArrayList");
|
||||
ALLOWLIST_CLASS_NAMES = Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -21,19 +21,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPerson;
|
||||
|
||||
/**
|
||||
* This is a Jackson mixin class helps in serialize/deserialize
|
||||
* {@link org.springframework.security.ldap.userdetails.InetOrgPerson} class. To use this
|
||||
* class you need to register it with {@link com.fasterxml.jackson.databind.ObjectMapper}.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new LdapJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* <i>Note: This class will save full class name into a property called @class</i>
|
||||
* This Jackson mixin is used to serialize/deserialize {@link InetOrgPerson}.
|
||||
*
|
||||
* @since 5.7
|
||||
* @see LdapJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -26,19 +26,12 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthority;
|
||||
|
||||
/**
|
||||
* This is a Jackson mixin class helps in serialize/deserialize
|
||||
* {@link org.springframework.security.ldap.userdetails.LdapAuthority} class. To use this
|
||||
* class you need to register it with {@link com.fasterxml.jackson.databind.ObjectMapper}.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new LdapJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* <i>Note: This class will save full class name into a property called @class</i>
|
||||
* This Jackson mixin is used to serialize/deserialize {@link LdapAuthority}.
|
||||
*
|
||||
* @since 5.7
|
||||
* @see LdapJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
|
@ -47,13 +40,6 @@ import org.springframework.security.jackson2.SecurityJackson2Modules;
|
|||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
abstract class LdapAuthorityMixin {
|
||||
|
||||
/**
|
||||
* Constructor used by Jackson to create object of
|
||||
* {@link org.springframework.security.ldap.userdetails.LdapAuthority}.
|
||||
* @param role
|
||||
* @param dn
|
||||
* @param attributes
|
||||
*/
|
||||
@JsonCreator
|
||||
LdapAuthorityMixin(@JsonProperty("role") String role, @JsonProperty("dn") String dn,
|
||||
@JsonProperty("attributes") Map<String, List<String>> attributes) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -26,11 +26,13 @@ import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
|
|||
import org.springframework.security.ldap.userdetails.Person;
|
||||
|
||||
/**
|
||||
* Jackson module for spring-security-ldap. This module registers
|
||||
* Jackson module for {@code spring-security-ldap}. This module registers
|
||||
* {@link LdapAuthorityMixin}, {@link LdapUserDetailsImplMixin}, {@link PersonMixin},
|
||||
* {@link InetOrgPersonMixin}. If no default typing enabled by default then it'll enable
|
||||
* it because typing info is needed to properly serialize/deserialize objects. In order to
|
||||
* use this module just add this module into your ObjectMapper configuration.
|
||||
* {@link InetOrgPersonMixin}.
|
||||
*
|
||||
* If not already enabled, default typing will be automatically enabled as type info is
|
||||
* required to properly serialize/deserialize objects. In order to use this module just
|
||||
* add it to your {@code ObjectMapper} configuration.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
|
@ -40,6 +42,7 @@ import org.springframework.security.ldap.userdetails.Person;
|
|||
* <b>Note: use {@link SecurityJackson2Modules#getModules(ClassLoader)} to get list of all
|
||||
* security modules.</b>
|
||||
*
|
||||
* @since 5.7
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
public class LdapJackson2Module extends SimpleModule {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -21,20 +21,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
|
||||
|
||||
/**
|
||||
* This is a Jackson mixin class helps in serialize/deserialize
|
||||
* {@link org.springframework.security.ldap.userdetails.LdapUserDetailsImpl} class. To use
|
||||
* this class you need to register it with
|
||||
* {@link com.fasterxml.jackson.databind.ObjectMapper}.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new LdapJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* <i>Note: This class will save full class name into a property called @class</i>
|
||||
* This Jackson mixin is used to serialize/deserialize {@link LdapUserDetailsImpl}.
|
||||
*
|
||||
* @since 5.7
|
||||
* @see LdapJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2020 the original author or authors.
|
||||
* Copyright 2015-2021 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.
|
||||
|
@ -21,19 +21,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.Person;
|
||||
|
||||
/**
|
||||
* This is a Jackson mixin class helps in serialize/deserialize
|
||||
* {@link org.springframework.security.ldap.userdetails.Person} class. To use this class
|
||||
* you need to register it with {@link com.fasterxml.jackson.databind.ObjectMapper}.
|
||||
*
|
||||
* <pre>
|
||||
* ObjectMapper mapper = new ObjectMapper();
|
||||
* mapper.registerModule(new LdapJackson2Module());
|
||||
* </pre>
|
||||
*
|
||||
* <i>Note: This class will save full class name into a property called @class</i>
|
||||
* This Jackson mixin is used to serialize/deserialize {@link Person}.
|
||||
*
|
||||
* @since 5.7
|
||||
* @see LdapJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
@ -13,27 +13,74 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.jackson2;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPerson;
|
||||
import org.springframework.security.ldap.userdetails.Person;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPerson;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link InetOrgPersonMixin}.
|
||||
*/
|
||||
class InetOrgPersonMixinTests {
|
||||
public class InetOrgPersonMixinTests {
|
||||
|
||||
private static final String USER_PASSWORD = "Password1234";
|
||||
|
||||
private static final String AUTHORITIES_ARRAYLIST_JSON = "[\"java.util.Collections$UnmodifiableRandomAccessList\", []]";
|
||||
|
||||
// @formatter:off
|
||||
private static final String INET_ORG_PERSON_JSON = "{\n"
|
||||
+ "\"@class\": \"org.springframework.security.ldap.userdetails.InetOrgPerson\","
|
||||
+ "\"dn\": \"ignored=ignored\","
|
||||
+ "\"uid\": \"ghengis\","
|
||||
+ "\"username\": \"ghengis\","
|
||||
+ "\"password\": \"" + USER_PASSWORD + "\","
|
||||
+ "\"carLicense\": \"HORS1\","
|
||||
+ "\"givenName\": \"Ghengis\","
|
||||
+ "\"destinationIndicator\": \"West\","
|
||||
+ "\"displayName\": \"Ghengis McCann\","
|
||||
+ "\"givenName\": \"Ghengis\","
|
||||
+ "\"homePhone\": \"+467575436521\","
|
||||
+ "\"initials\": \"G\","
|
||||
+ "\"employeeNumber\": \"00001\","
|
||||
+ "\"homePostalAddress\": \"Steppes\","
|
||||
+ "\"mail\": \"ghengis@mongolia\","
|
||||
+ "\"mobile\": \"always\","
|
||||
+ "\"o\": \"Hordes\","
|
||||
+ "\"ou\": \"Horde1\","
|
||||
+ "\"postalAddress\": \"On the Move\","
|
||||
+ "\"postalCode\": \"Changes Frequently\","
|
||||
+ "\"roomNumber\": \"Yurt 1\","
|
||||
+ "\"sn\": \"Khan\","
|
||||
+ "\"street\": \"Westward Avenue\","
|
||||
+ "\"telephoneNumber\": \"+442075436521\","
|
||||
+ "\"departmentNumber\": \"5679\","
|
||||
+ "\"title\": \"T\","
|
||||
+ "\"cn\": [\"java.util.Arrays$ArrayList\",[\"Ghengis Khan\"]],"
|
||||
+ "\"description\": \"Scary\","
|
||||
+ "\"accountNonExpired\": true, "
|
||||
+ "\"accountNonLocked\": true, "
|
||||
+ "\"credentialsNonExpired\": true, "
|
||||
+ "\"enabled\": true, "
|
||||
+ "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + ","
|
||||
+ "\"graceLoginsRemaining\": " + Integer.MAX_VALUE + ","
|
||||
+ "\"timeBeforeExpiration\": " + Integer.MAX_VALUE
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
|
||||
private ObjectMapper mapper;
|
||||
|
||||
|
@ -44,22 +91,83 @@ class InetOrgPersonMixinTests {
|
|||
this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
public void serializeWhenMixinRegisteredThenSerializes() throws Exception {
|
||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||
InetOrgPersonContextMapper mapper = new InetOrgPersonContextMapper();
|
||||
InetOrgPerson p = (InetOrgPerson) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
String expectedJson = asJson(p);
|
||||
String json = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(expectedJson, json, true);
|
||||
JSONAssert.assertEquals(INET_ORG_PERSON_JSON, json, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeWhenEraseCredentialInvokedThenUserPasswordIsNull()
|
||||
throws JsonProcessingException, JSONException {
|
||||
InetOrgPersonContextMapper mapper = new InetOrgPersonContextMapper();
|
||||
InetOrgPerson p = (InetOrgPerson) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
p.eraseCredentials();
|
||||
String actualJson = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(INET_ORG_PERSON_JSON.replaceAll("\"" + USER_PASSWORD + "\"", "null"), actualJson, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinNotRegisteredThenThrowJsonProcessingException() {
|
||||
assertThatExceptionOfType(JsonProcessingException.class)
|
||||
.isThrownBy(() -> new ObjectMapper().readValue(INET_ORG_PERSON_JSON, InetOrgPerson.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinRegisteredThenDeserializes() throws Exception {
|
||||
InetOrgPersonContextMapper mapper = new InetOrgPersonContextMapper();
|
||||
InetOrgPerson expectedAuthentication = (InetOrgPerson) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
InetOrgPerson authentication = this.mapper.readValue(INET_ORG_PERSON_JSON, InetOrgPerson.class);
|
||||
assertThat(authentication.getAuthorities()).containsExactlyElementsOf(expectedAuthentication.getAuthorities());
|
||||
assertThat(authentication.getCarLicense()).isEqualTo(expectedAuthentication.getCarLicense());
|
||||
assertThat(authentication.getDepartmentNumber()).isEqualTo(expectedAuthentication.getDepartmentNumber());
|
||||
assertThat(authentication.getDestinationIndicator())
|
||||
.isEqualTo(expectedAuthentication.getDestinationIndicator());
|
||||
assertThat(authentication.getDn()).isEqualTo(expectedAuthentication.getDn());
|
||||
assertThat(authentication.getDescription()).isEqualTo(expectedAuthentication.getDescription());
|
||||
assertThat(authentication.getDisplayName()).isEqualTo(expectedAuthentication.getDisplayName());
|
||||
assertThat(authentication.getUid()).isEqualTo(expectedAuthentication.getUid());
|
||||
assertThat(authentication.getUsername()).isEqualTo(expectedAuthentication.getUsername());
|
||||
assertThat(authentication.getPassword()).isEqualTo(expectedAuthentication.getPassword());
|
||||
assertThat(authentication.getHomePhone()).isEqualTo(expectedAuthentication.getHomePhone());
|
||||
assertThat(authentication.getEmployeeNumber()).isEqualTo(expectedAuthentication.getEmployeeNumber());
|
||||
assertThat(authentication.getHomePostalAddress()).isEqualTo(expectedAuthentication.getHomePostalAddress());
|
||||
assertThat(authentication.getInitials()).isEqualTo(expectedAuthentication.getInitials());
|
||||
assertThat(authentication.getMail()).isEqualTo(expectedAuthentication.getMail());
|
||||
assertThat(authentication.getMobile()).isEqualTo(expectedAuthentication.getMobile());
|
||||
assertThat(authentication.getO()).isEqualTo(expectedAuthentication.getO());
|
||||
assertThat(authentication.getOu()).isEqualTo(expectedAuthentication.getOu());
|
||||
assertThat(authentication.getPostalAddress()).isEqualTo(expectedAuthentication.getPostalAddress());
|
||||
assertThat(authentication.getPostalCode()).isEqualTo(expectedAuthentication.getPostalCode());
|
||||
assertThat(authentication.getRoomNumber()).isEqualTo(expectedAuthentication.getRoomNumber());
|
||||
assertThat(authentication.getStreet()).isEqualTo(expectedAuthentication.getStreet());
|
||||
assertThat(authentication.getSn()).isEqualTo(expectedAuthentication.getSn());
|
||||
assertThat(authentication.getTitle()).isEqualTo(expectedAuthentication.getTitle());
|
||||
assertThat(authentication.getGivenName()).isEqualTo(expectedAuthentication.getGivenName());
|
||||
assertThat(authentication.getTelephoneNumber()).isEqualTo(expectedAuthentication.getTelephoneNumber());
|
||||
assertThat(authentication.getGraceLoginsRemaining())
|
||||
.isEqualTo(expectedAuthentication.getGraceLoginsRemaining());
|
||||
assertThat(authentication.getTimeBeforeExpiration())
|
||||
.isEqualTo(expectedAuthentication.getTimeBeforeExpiration());
|
||||
assertThat(authentication.isAccountNonExpired()).isEqualTo(expectedAuthentication.isAccountNonExpired());
|
||||
assertThat(authentication.isAccountNonLocked()).isEqualTo(expectedAuthentication.isAccountNonLocked());
|
||||
assertThat(authentication.isEnabled()).isEqualTo(expectedAuthentication.isEnabled());
|
||||
assertThat(authentication.isCredentialsNonExpired())
|
||||
.isEqualTo(expectedAuthentication.isCredentialsNonExpired());
|
||||
}
|
||||
|
||||
private DirContextAdapter createUserContext() {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
ctx.setDn(new DistinguishedName("ignored=ignored"));
|
||||
ctx.setAttributeValue("uid", "ghengis");
|
||||
ctx.setAttributeValue("userPassword", "pillage");
|
||||
ctx.setAttributeValue("userPassword", USER_PASSWORD);
|
||||
ctx.setAttributeValue("carLicense", "HORS1");
|
||||
ctx.setAttributeValue("cn", "Ghengis Khan");
|
||||
ctx.setAttributeValue("description", "Scary");
|
||||
|
@ -77,19 +185,12 @@ class InetOrgPersonMixinTests {
|
|||
ctx.setAttributeValue("postalAddress", "On the Move");
|
||||
ctx.setAttributeValue("postalCode", "Changes Frequently");
|
||||
ctx.setAttributeValue("roomNumber", "Yurt 1");
|
||||
ctx.setAttributeValue("roomNumber", "Yurt 1");
|
||||
ctx.setAttributeValue("sn", "Khan");
|
||||
ctx.setAttributeValue("street", "Westward Avenue");
|
||||
ctx.setAttributeValue("telephoneNumber", "+442075436521");
|
||||
ctx.setAttributeValue("departmentNumber", "5679");
|
||||
ctx.setAttributeValue("title", "T");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
private String asJson(Person person) {
|
||||
// @formatter:off
|
||||
return "{\n" +
|
||||
" \"@class\": \"org.springframework.security.ldap.userdetails.InetOrgPerson\"\n" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.ldap.jackson2;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Tests for {@link LdapAuthorityMixin}.
|
||||
*/
|
||||
class LdapAuthorityMixinTests {
|
||||
|
||||
}
|
|
@ -13,13 +13,114 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.jackson2;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
|
||||
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link LdapUserDetailsImplMixin}.
|
||||
*/
|
||||
class LdapUserDetailsImplMixinTests {
|
||||
public class LdapUserDetailsImplMixinTests {
|
||||
|
||||
private static final String USER_PASSWORD = "Password1234";
|
||||
|
||||
private static final String AUTHORITIES_ARRAYLIST_JSON = "[\"java.util.Collections$UnmodifiableRandomAccessList\", []]";
|
||||
|
||||
// @formatter:off
|
||||
private static final String USER_JSON = "{"
|
||||
+ "\"@class\": \"org.springframework.security.ldap.userdetails.LdapUserDetailsImpl\", "
|
||||
+ "\"dn\": \"ignored=ignored\","
|
||||
+ "\"username\": \"ghengis\","
|
||||
+ "\"password\": \"" + USER_PASSWORD + "\","
|
||||
+ "\"accountNonExpired\": true, "
|
||||
+ "\"accountNonLocked\": true, "
|
||||
+ "\"credentialsNonExpired\": true, "
|
||||
+ "\"enabled\": true, "
|
||||
+ "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + ","
|
||||
+ "\"graceLoginsRemaining\": " + Integer.MAX_VALUE + ","
|
||||
+ "\"timeBeforeExpiration\": " + Integer.MAX_VALUE
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
ClassLoader loader = getClass().getClassLoader();
|
||||
this.mapper = new ObjectMapper();
|
||||
this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeWhenMixinRegisteredThenSerializes() throws Exception {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
LdapUserDetailsImpl p = (LdapUserDetailsImpl) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
String json = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(USER_JSON, json, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeWhenEraseCredentialInvokedThenUserPasswordIsNull()
|
||||
throws JsonProcessingException, JSONException {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
LdapUserDetailsImpl p = (LdapUserDetailsImpl) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
p.eraseCredentials();
|
||||
String actualJson = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(USER_JSON.replaceAll("\"" + USER_PASSWORD + "\"", "null"), actualJson, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinNotRegisteredThenThrowJsonProcessingException() {
|
||||
assertThatExceptionOfType(JsonProcessingException.class)
|
||||
.isThrownBy(() -> new ObjectMapper().readValue(USER_JSON, LdapUserDetailsImpl.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinRegisteredThenDeserializes() throws Exception {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
LdapUserDetailsImpl expectedAuthentication = (LdapUserDetailsImpl) mapper
|
||||
.mapUserFromContext(createUserContext(), "ghengis", AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
LdapUserDetailsImpl authentication = this.mapper.readValue(USER_JSON, LdapUserDetailsImpl.class);
|
||||
assertThat(authentication.getAuthorities()).containsExactlyElementsOf(expectedAuthentication.getAuthorities());
|
||||
assertThat(authentication.getDn()).isEqualTo(expectedAuthentication.getDn());
|
||||
assertThat(authentication.getUsername()).isEqualTo(expectedAuthentication.getUsername());
|
||||
assertThat(authentication.getPassword()).isEqualTo(expectedAuthentication.getPassword());
|
||||
assertThat(authentication.getGraceLoginsRemaining())
|
||||
.isEqualTo(expectedAuthentication.getGraceLoginsRemaining());
|
||||
assertThat(authentication.getTimeBeforeExpiration())
|
||||
.isEqualTo(expectedAuthentication.getTimeBeforeExpiration());
|
||||
assertThat(authentication.isAccountNonExpired()).isEqualTo(expectedAuthentication.isAccountNonExpired());
|
||||
assertThat(authentication.isAccountNonLocked()).isEqualTo(expectedAuthentication.isAccountNonLocked());
|
||||
assertThat(authentication.isEnabled()).isEqualTo(expectedAuthentication.isEnabled());
|
||||
assertThat(authentication.isCredentialsNonExpired())
|
||||
.isEqualTo(expectedAuthentication.isCredentialsNonExpired());
|
||||
}
|
||||
|
||||
private DirContextAdapter createUserContext() {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
ctx.setDn(new DistinguishedName("ignored=ignored"));
|
||||
ctx.setAttributeValue("userPassword", USER_PASSWORD);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
@ -13,23 +13,55 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.jackson2;
|
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.Person;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.ldap.userdetails.Person;
|
||||
import org.springframework.security.ldap.userdetails.PersonContextMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link PersonMixin}.
|
||||
*/
|
||||
class PersonMixinTests {
|
||||
public class PersonMixinTests {
|
||||
|
||||
private static final String USER_PASSWORD = "Password1234";
|
||||
|
||||
private static final String AUTHORITIES_ARRAYLIST_JSON = "[\"java.util.Collections$UnmodifiableRandomAccessList\", []]";
|
||||
|
||||
// @formatter:off
|
||||
private static final String PERSON_JSON = "{"
|
||||
+ "\"@class\": \"org.springframework.security.ldap.userdetails.Person\", "
|
||||
+ "\"dn\": \"ignored=ignored\","
|
||||
+ "\"username\": \"ghengis\","
|
||||
+ "\"password\": \"" + USER_PASSWORD + "\","
|
||||
+ "\"givenName\": \"Ghengis\","
|
||||
+ "\"sn\": \"Khan\","
|
||||
+ "\"cn\": [\"java.util.Arrays$ArrayList\",[\"Ghengis Khan\"]],"
|
||||
+ "\"description\": \"Scary\","
|
||||
+ "\"telephoneNumber\": \"+442075436521\","
|
||||
+ "\"accountNonExpired\": true, "
|
||||
+ "\"accountNonLocked\": true, "
|
||||
+ "\"credentialsNonExpired\": true, "
|
||||
+ "\"enabled\": true, "
|
||||
+ "\"authorities\": " + AUTHORITIES_ARRAYLIST_JSON + ","
|
||||
+ "\"graceLoginsRemaining\": " + Integer.MAX_VALUE + ","
|
||||
+ "\"timeBeforeExpiration\": " + Integer.MAX_VALUE
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
|
||||
private ObjectMapper mapper;
|
||||
|
||||
|
@ -40,20 +72,67 @@ class PersonMixinTests {
|
|||
this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
|
||||
}
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
public void serializeWhenMixinRegisteredThenSerializes() throws Exception {
|
||||
Person person = null;
|
||||
String expectedJson = asJson(person);
|
||||
String json = this.mapper.writeValueAsString(person);
|
||||
JSONAssert.assertEquals(expectedJson, json, true);
|
||||
PersonContextMapper mapper = new PersonContextMapper();
|
||||
Person p = (Person) mapper.mapUserFromContext(createUserContext(), "ghengis", AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
String json = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(PERSON_JSON, json, true);
|
||||
}
|
||||
|
||||
private String asJson(Person person) {
|
||||
// @formatter:off
|
||||
return "{\n" +
|
||||
" \"@class\": \"org.springframework.security.ldap.userdetails.Person\"\n" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void serializeWhenEraseCredentialInvokedThenUserPasswordIsNull()
|
||||
throws JsonProcessingException, JSONException {
|
||||
PersonContextMapper mapper = new PersonContextMapper();
|
||||
Person p = (Person) mapper.mapUserFromContext(createUserContext(), "ghengis", AuthorityUtils.NO_AUTHORITIES);
|
||||
p.eraseCredentials();
|
||||
String actualJson = this.mapper.writeValueAsString(p);
|
||||
JSONAssert.assertEquals(PERSON_JSON.replaceAll("\"" + USER_PASSWORD + "\"", "null"), actualJson, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinNotRegisteredThenThrowJsonProcessingException() {
|
||||
assertThatExceptionOfType(JsonProcessingException.class)
|
||||
.isThrownBy(() -> new ObjectMapper().readValue(PERSON_JSON, Person.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializeWhenMixinRegisteredThenDeserializes() throws Exception {
|
||||
PersonContextMapper mapper = new PersonContextMapper();
|
||||
Person expectedAuthentication = (Person) mapper.mapUserFromContext(createUserContext(), "ghengis",
|
||||
AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
Person authentication = this.mapper.readValue(PERSON_JSON, Person.class);
|
||||
assertThat(authentication.getAuthorities()).containsExactlyElementsOf(expectedAuthentication.getAuthorities());
|
||||
assertThat(authentication.getDn()).isEqualTo(expectedAuthentication.getDn());
|
||||
assertThat(authentication.getDescription()).isEqualTo(expectedAuthentication.getDescription());
|
||||
assertThat(authentication.getUsername()).isEqualTo(expectedAuthentication.getUsername());
|
||||
assertThat(authentication.getPassword()).isEqualTo(expectedAuthentication.getPassword());
|
||||
assertThat(authentication.getSn()).isEqualTo(expectedAuthentication.getSn());
|
||||
assertThat(authentication.getGivenName()).isEqualTo(expectedAuthentication.getGivenName());
|
||||
assertThat(authentication.getTelephoneNumber()).isEqualTo(expectedAuthentication.getTelephoneNumber());
|
||||
assertThat(authentication.getGraceLoginsRemaining())
|
||||
.isEqualTo(expectedAuthentication.getGraceLoginsRemaining());
|
||||
assertThat(authentication.getTimeBeforeExpiration())
|
||||
.isEqualTo(expectedAuthentication.getTimeBeforeExpiration());
|
||||
assertThat(authentication.isAccountNonExpired()).isEqualTo(expectedAuthentication.isAccountNonExpired());
|
||||
assertThat(authentication.isAccountNonLocked()).isEqualTo(expectedAuthentication.isAccountNonLocked());
|
||||
assertThat(authentication.isEnabled()).isEqualTo(expectedAuthentication.isEnabled());
|
||||
assertThat(authentication.isCredentialsNonExpired())
|
||||
.isEqualTo(expectedAuthentication.isCredentialsNonExpired());
|
||||
}
|
||||
|
||||
private DirContextAdapter createUserContext() {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
ctx.setDn(new DistinguishedName("ignored=ignored"));
|
||||
ctx.setAttributeValue("userPassword", USER_PASSWORD);
|
||||
ctx.setAttributeValue("cn", "Ghengis Khan");
|
||||
ctx.setAttributeValue("description", "Scary");
|
||||
ctx.setAttributeValue("givenName", "Ghengis");
|
||||
ctx.setAttributeValue("sn", "Khan");
|
||||
ctx.setAttributeValue("telephoneNumber", "+442075436521");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue