parent
df84826c95
commit
6c3d183a94
|
@ -47,7 +47,7 @@ class UnmodifiableMapDeserializerTests extends AbstractMixinTests {
|
||||||
Collections.unmodifiableMap(Collections.emptyMap()).getClass());
|
Collections.unmodifiableMap(Collections.emptyMap()).getClass());
|
||||||
|
|
||||||
assertThat(map).isNotNull().isInstanceOf(Collections.unmodifiableMap(Collections.emptyMap()).getClass())
|
assertThat(map).isNotNull().isInstanceOf(Collections.unmodifiableMap(Collections.emptyMap()).getClass())
|
||||||
.containsAllEntriesOf(Map.of("Key", "Value"));
|
.containsAllEntriesOf(Collections.singletonMap("Key", "Value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom deserializer for {@link DefaultSaml2AuthenticatedPrincipal}.
|
|
||||||
*
|
|
||||||
* @author Ulrich Grave
|
|
||||||
* @since 5.7
|
|
||||||
* @see DefaultSaml2AuthenticatedPrincipalMixin
|
|
||||||
*/
|
|
||||||
class DefaultSaml2AuthenticatedPrincipalDeserializer extends JsonDeserializer<DefaultSaml2AuthenticatedPrincipal> {
|
|
||||||
|
|
||||||
private static final TypeReference<List<String>> SESSION_INDICES_LIST = new TypeReference<List<String>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final TypeReference<Map<String, List<Object>>> ATTRIBUTES_MAP = new TypeReference<Map<String, List<Object>>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DefaultSaml2AuthenticatedPrincipal deserialize(JsonParser jp, DeserializationContext ctxt)
|
|
||||||
throws IOException {
|
|
||||||
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
|
|
||||||
JsonNode jsonNode = mapper.readTree(jp);
|
|
||||||
|
|
||||||
String name = JsonNodeUtils.findStringValue(jsonNode, "name");
|
|
||||||
Map<String, List<Object>> attributes = JsonNodeUtils.findValue(jsonNode, "attributes", ATTRIBUTES_MAP, mapper);
|
|
||||||
List<String> sessionIndexes = JsonNodeUtils.findValue(jsonNode, "sessionIndexes", SESSION_INDICES_LIST, mapper);
|
|
||||||
String registrationId = JsonNodeUtils.findStringValue(jsonNode, "registrationId");
|
|
||||||
|
|
||||||
DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(name, attributes,
|
|
||||||
sessionIndexes);
|
|
||||||
if (registrationId != null) {
|
|
||||||
principal.setRelyingPartyRegistrationId(registrationId);
|
|
||||||
}
|
|
||||||
return principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,9 +16,13 @@
|
||||||
|
|
||||||
package org.springframework.security.saml2.jackson2;
|
package org.springframework.security.saml2.jackson2;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|
||||||
|
|
||||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
|
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
|
||||||
|
@ -40,7 +44,16 @@ import org.springframework.security.saml2.provider.service.authentication.Defaul
|
||||||
*/
|
*/
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||||
@JsonDeserialize(using = DefaultSaml2AuthenticatedPrincipalDeserializer.class)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
class DefaultSaml2AuthenticatedPrincipalMixin {
|
class DefaultSaml2AuthenticatedPrincipalMixin {
|
||||||
|
|
||||||
|
@JsonProperty("registrationId")
|
||||||
|
String registrationId;
|
||||||
|
|
||||||
|
DefaultSaml2AuthenticatedPrincipalMixin(@JsonProperty("name") String name,
|
||||||
|
@JsonProperty("attributes") Map<String, List<Object>> attributes,
|
||||||
|
@JsonProperty("sessionIndexes") List<String> sessionIndexes) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.node.MissingNode;
|
|
||||||
|
|
||||||
final class JsonNodeUtils {
|
|
||||||
|
|
||||||
private JsonNodeUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static String findStringValue(JsonNode jsonNode, String fieldName) {
|
|
||||||
if (jsonNode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
JsonNode value = jsonNode.findValue(fieldName);
|
|
||||||
return (value != null && value.isTextual()) ? value.asText() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static <T> T findValue(JsonNode jsonNode, String fieldName, TypeReference<T> valueTypeReference,
|
|
||||||
ObjectMapper mapper) {
|
|
||||||
if (jsonNode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
JsonNode value = jsonNode.findValue(fieldName);
|
|
||||||
return (value != null && value.isContainerNode()) ? mapper.convertValue(value, valueTypeReference) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static JsonNode readJsonNode(JsonNode jsonNode, String field) {
|
|
||||||
return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom deserializer for {@link Saml2Authentication}.
|
|
||||||
*
|
|
||||||
* @author Ulrich Grave
|
|
||||||
* @since 5.7
|
|
||||||
* @see Saml2AuthenticationMixin
|
|
||||||
*/
|
|
||||||
class Saml2AuthenticationDeserializer extends JsonDeserializer<Saml2Authentication> {
|
|
||||||
|
|
||||||
private static final TypeReference<List<GrantedAuthority>> GRANTED_AUTHORITY_LIST = new TypeReference<List<GrantedAuthority>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final TypeReference<Object> OBJECT = new TypeReference<Object>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Saml2Authentication deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
|
|
||||||
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
|
|
||||||
JsonNode jsonNode = mapper.readTree(jp);
|
|
||||||
|
|
||||||
boolean authenticated = JsonNodeUtils.readJsonNode(jsonNode, "authenticated").asBoolean();
|
|
||||||
JsonNode principalNode = JsonNodeUtils.readJsonNode(jsonNode, "principal");
|
|
||||||
AuthenticatedPrincipal principal = getPrincipal(mapper, principalNode);
|
|
||||||
String saml2Response = JsonNodeUtils.findStringValue(jsonNode, "saml2Response");
|
|
||||||
List<GrantedAuthority> authorities = JsonNodeUtils.findValue(jsonNode, "authorities", GRANTED_AUTHORITY_LIST,
|
|
||||||
mapper);
|
|
||||||
Object details = JsonNodeUtils.findValue(jsonNode, "details", OBJECT, mapper);
|
|
||||||
|
|
||||||
Saml2Authentication authentication = new Saml2Authentication(principal, saml2Response, authorities);
|
|
||||||
authentication.setAuthenticated(authenticated);
|
|
||||||
authentication.setDetails(details);
|
|
||||||
return authentication;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthenticatedPrincipal getPrincipal(ObjectMapper mapper, JsonNode principalNode) throws IOException {
|
|
||||||
return mapper.readValue(principalNode.traverse(mapper), AuthenticatedPrincipal.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,10 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.security.saml2.jackson2;
|
package org.springframework.security.saml2.jackson2;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import java.util.Collection;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|
||||||
|
|
||||||
|
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.core.AuthenticatedPrincipal;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||||
|
|
||||||
|
@ -40,7 +46,13 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||||
@JsonDeserialize(using = Saml2AuthenticationDeserializer.class)
|
@JsonIgnoreProperties(value = { "authenticated" }, ignoreUnknown = true)
|
||||||
class Saml2AuthenticationMixin {
|
class Saml2AuthenticationMixin {
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
Saml2AuthenticationMixin(@JsonProperty("principal") AuthenticatedPrincipal principal,
|
||||||
|
@JsonProperty("saml2Response") String saml2Response,
|
||||||
|
@JsonProperty("authorities") Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,6 @@ final class TestSaml2JsonPayloads {
|
||||||
+ " \"credentialsNonExpired\": true,"
|
+ " \"credentialsNonExpired\": true,"
|
||||||
+ " \"enabled\": true"
|
+ " \"enabled\": true"
|
||||||
+ " },"
|
+ " },"
|
||||||
+ " \"authenticated\": true,"
|
|
||||||
+ " \"principal\": " + DEFAULT_AUTHENTICATED_PRINCIPAL_JSON + ","
|
+ " \"principal\": " + DEFAULT_AUTHENTICATED_PRINCIPAL_JSON + ","
|
||||||
+ " \"saml2Response\": \"" + SAML_RESPONSE + "\""
|
+ " \"saml2Response\": \"" + SAML_RESPONSE + "\""
|
||||||
+ "}";
|
+ "}";
|
||||||
|
|
Loading…
Reference in New Issue