20 changed files with 1430 additions and 200 deletions
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.ConversionService; |
||||||
|
import org.springframework.core.convert.converter.ConverterRegistry; |
||||||
|
import org.springframework.core.convert.support.GenericConversionService; |
||||||
|
import org.springframework.security.oauth2.core.ClaimAccessor; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link ConversionService} configured with converters |
||||||
|
* that provide type conversion for claim values. |
||||||
|
* |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
* @see GenericConversionService |
||||||
|
* @see ClaimAccessor |
||||||
|
*/ |
||||||
|
public final class ClaimConversionService extends GenericConversionService { |
||||||
|
private static volatile ClaimConversionService sharedInstance; |
||||||
|
|
||||||
|
private ClaimConversionService() { |
||||||
|
addConverters(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a shared instance of {@code ClaimConversionService}. |
||||||
|
* |
||||||
|
* @return a shared instance of {@code ClaimConversionService} |
||||||
|
*/ |
||||||
|
public static ClaimConversionService getSharedInstance() { |
||||||
|
ClaimConversionService sharedInstance = ClaimConversionService.sharedInstance; |
||||||
|
if (sharedInstance == null) { |
||||||
|
synchronized (ClaimConversionService.class) { |
||||||
|
sharedInstance = ClaimConversionService.sharedInstance; |
||||||
|
if (sharedInstance == null) { |
||||||
|
sharedInstance = new ClaimConversionService(); |
||||||
|
ClaimConversionService.sharedInstance = sharedInstance; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return sharedInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the converters that provide type conversion for claim values |
||||||
|
* to the provided {@link ConverterRegistry}. |
||||||
|
* |
||||||
|
* @param converterRegistry the registry of converters to add to |
||||||
|
*/ |
||||||
|
public static void addConverters(ConverterRegistry converterRegistry) { |
||||||
|
converterRegistry.addConverter(new ObjectToStringConverter()); |
||||||
|
converterRegistry.addConverter(new ObjectToBooleanConverter()); |
||||||
|
converterRegistry.addConverter(new ObjectToInstantConverter()); |
||||||
|
converterRegistry.addConverter(new ObjectToURLConverter()); |
||||||
|
converterRegistry.addConverter(new ObjectToListStringConverter()); |
||||||
|
converterRegistry.addConverter(new ObjectToMapStringObjectConverter()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.CollectionUtils; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link Converter} that provides type conversion for claim values. |
||||||
|
* |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
* @see Converter |
||||||
|
*/ |
||||||
|
public final class ClaimTypeConverter implements Converter<Map<String, Object>, Map<String, Object>> { |
||||||
|
private final Map<String, Converter<Object, ?>> claimTypeConverters; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructs a {@code ClaimTypeConverter} using the provided parameters. |
||||||
|
* |
||||||
|
* @param claimTypeConverters a {@link Map} of {@link Converter}(s) keyed by claim name |
||||||
|
*/ |
||||||
|
public ClaimTypeConverter(Map<String, Converter<Object, ?>> claimTypeConverters) { |
||||||
|
Assert.notEmpty(claimTypeConverters, "claimTypeConverters cannot be empty"); |
||||||
|
Assert.noNullElements(claimTypeConverters.values().toArray(), "Converter(s) cannot be null"); |
||||||
|
this.claimTypeConverters = Collections.unmodifiableMap(new LinkedHashMap<>(claimTypeConverters)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Map<String, Object> convert(Map<String, Object> claims) { |
||||||
|
if (CollectionUtils.isEmpty(claims)) { |
||||||
|
return claims; |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(claims); |
||||||
|
this.claimTypeConverters.forEach((claimName, typeConverter) -> { |
||||||
|
if (claims.containsKey(claimName)) { |
||||||
|
Object claim = claims.get(claimName); |
||||||
|
Object mappedClaim = typeConverter.convert(claim); |
||||||
|
if (mappedClaim != null) { |
||||||
|
result.put(claimName, mappedClaim); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,45 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.GenericConverter; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToBooleanConverter implements GenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
return Collections.singleton(new ConvertiblePair(Object.class, Boolean.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (source instanceof Boolean) { |
||||||
|
return source; |
||||||
|
} |
||||||
|
return Boolean.valueOf(source.toString()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.GenericConverter; |
||||||
|
|
||||||
|
import java.time.Instant; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToInstantConverter implements GenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
return Collections.singleton(new ConvertiblePair(Object.class, Instant.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (source instanceof Instant) { |
||||||
|
return source; |
||||||
|
} |
||||||
|
if (source instanceof Date) { |
||||||
|
return ((Date) source).toInstant(); |
||||||
|
} |
||||||
|
if (source instanceof Number) { |
||||||
|
return Instant.ofEpochSecond(((Number) source).longValue()); |
||||||
|
} |
||||||
|
try { |
||||||
|
return Instant.ofEpochSecond(Long.parseLong(source.toString())); |
||||||
|
} catch (Exception ex) { |
||||||
|
// Ignore
|
||||||
|
} |
||||||
|
try { |
||||||
|
return Instant.parse(source.toString()); |
||||||
|
} catch (Exception ex) { |
||||||
|
// Ignore
|
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.ConditionalGenericConverter; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.LinkedHashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToListStringConverter implements ConditionalGenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
Set<ConvertiblePair> convertibleTypes = new LinkedHashSet<>(); |
||||||
|
convertibleTypes.add(new ConvertiblePair(Object.class, List.class)); |
||||||
|
convertibleTypes.add(new ConvertiblePair(Object.class, Collection.class)); |
||||||
|
return convertibleTypes; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (targetType.getElementTypeDescriptor() == null || |
||||||
|
targetType.getElementTypeDescriptor().getType().equals(String.class) || |
||||||
|
sourceType == null || |
||||||
|
ClassUtils.isAssignable(sourceType.getType(), targetType.getElementTypeDescriptor().getType())) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (source instanceof List) { |
||||||
|
List<?> sourceList = (List<?>) source; |
||||||
|
if (!sourceList.isEmpty() && sourceList.get(0) instanceof String) { |
||||||
|
return source; |
||||||
|
} |
||||||
|
} |
||||||
|
if (source instanceof Collection) { |
||||||
|
return ((Collection<?>) source).stream() |
||||||
|
.filter(Objects::nonNull) |
||||||
|
.map(Objects::toString) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
} |
||||||
|
return Collections.singletonList(source.toString()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.ConditionalGenericConverter; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToMapStringObjectConverter implements ConditionalGenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
return Collections.singleton(new ConvertiblePair(Object.class, Map.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (targetType.getElementTypeDescriptor() == null || |
||||||
|
targetType.getMapKeyTypeDescriptor().getType().equals(String.class)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (!(source instanceof Map)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
Map<?, ?> sourceMap = (Map<?, ?>) source; |
||||||
|
if (!sourceMap.isEmpty() && sourceMap.keySet().iterator().next() instanceof String) { |
||||||
|
return source; |
||||||
|
} |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
sourceMap.forEach((k, v) -> result.put(k.toString(), v)); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.GenericConverter; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToStringConverter implements GenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
return Collections.singleton(new ConvertiblePair(Object.class, String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
return source == null ? null : source.toString(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.GenericConverter; |
||||||
|
|
||||||
|
import java.net.URI; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
final class ObjectToURLConverter implements GenericConverter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Set<ConvertiblePair> getConvertibleTypes() { |
||||||
|
return Collections.singleton(new ConvertiblePair(Object.class, URL.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { |
||||||
|
if (source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (source instanceof URL) { |
||||||
|
return source; |
||||||
|
} |
||||||
|
try { |
||||||
|
return new URI(source.toString()).toURL(); |
||||||
|
} catch (Exception ex) { |
||||||
|
// Ignore
|
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,227 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.assertj.core.util.Lists; |
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.core.convert.ConversionService; |
||||||
|
|
||||||
|
import java.net.URL; |
||||||
|
import java.time.Instant; |
||||||
|
import java.time.temporal.ChronoUnit; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests for {@link ClaimConversionService}. |
||||||
|
* |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
public class ClaimConversionServiceTests { |
||||||
|
private final ConversionService conversionService = ClaimConversionService.getSharedInstance(); |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertStringWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, String.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertStringWhenStringThenReturnSame() { |
||||||
|
assertThat(this.conversionService.convert("string", String.class)).isSameAs("string"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertStringWhenNumberThenConverts() { |
||||||
|
assertThat(this.conversionService.convert(1234, String.class)).isEqualTo("1234"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertBooleanWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, Boolean.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertBooleanWhenBooleanThenReturnSame() { |
||||||
|
assertThat(this.conversionService.convert(Boolean.TRUE, Boolean.class)).isSameAs(Boolean.TRUE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertBooleanWhenStringTrueThenConverts() { |
||||||
|
assertThat(this.conversionService.convert("true", Boolean.class)).isEqualTo(Boolean.TRUE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertBooleanWhenNotConvertibleThenReturnBooleanFalse() { |
||||||
|
assertThat(this.conversionService.convert("not-convertible-boolean", Boolean.class)).isEqualTo(Boolean.FALSE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, Instant.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenInstantThenReturnSame() { |
||||||
|
Instant instant = Instant.now(); |
||||||
|
assertThat(this.conversionService.convert(instant, Instant.class)).isSameAs(instant); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenDateThenConverts() { |
||||||
|
Instant instant = Instant.now(); |
||||||
|
assertThat(this.conversionService.convert(Date.from(instant), Instant.class)).isEqualTo(instant); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenNumberThenConverts() { |
||||||
|
Instant instant = Instant.now(); |
||||||
|
assertThat(this.conversionService.convert(instant.getEpochSecond(), Instant.class)) |
||||||
|
.isEqualTo(instant.truncatedTo(ChronoUnit.SECONDS)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenStringThenConverts() { |
||||||
|
Instant instant = Instant.now(); |
||||||
|
assertThat(this.conversionService.convert(String.valueOf(instant.getEpochSecond()), Instant.class)) |
||||||
|
.isEqualTo(instant.truncatedTo(ChronoUnit.SECONDS)); |
||||||
|
assertThat(this.conversionService.convert(String.valueOf(instant.toString()), Instant.class)).isEqualTo(instant); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertInstantWhenNotConvertibleThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert("not-convertible-instant", Instant.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertUrlWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, URL.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertUrlWhenUrlThenReturnSame() throws Exception { |
||||||
|
URL url = new URL("https://localhost"); |
||||||
|
assertThat(this.conversionService.convert(url, URL.class)).isSameAs(url); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertUrlWhenStringThenConverts() throws Exception { |
||||||
|
String urlString = "https://localhost"; |
||||||
|
URL url = new URL(urlString); |
||||||
|
assertThat(this.conversionService.convert(urlString, URL.class)).isEqualTo(url); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertUrlWhenNotConvertibleThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert("not-convertible-url", URL.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertCollectionStringWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, Collection.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertCollectionStringWhenListStringThenReturnSame() { |
||||||
|
List<String> list = Lists.list("1", "2", "3", "4"); |
||||||
|
assertThat(this.conversionService.convert(list, Collection.class)).isSameAs(list); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertCollectionStringWhenListNumberThenConverts() { |
||||||
|
assertThat(this.conversionService.convert(Lists.list(1, 2, 3, 4), Collection.class)) |
||||||
|
.isEqualTo(Lists.list("1", "2", "3", "4")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertCollectionStringWhenNotConvertibleThenReturnSingletonList() { |
||||||
|
String string = "not-convertible-collection"; |
||||||
|
assertThat(this.conversionService.convert(string, Collection.class)) |
||||||
|
.isEqualTo(Collections.singletonList(string)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertListStringWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, List.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertListStringWhenListStringThenReturnSame() { |
||||||
|
List<String> list = Lists.list("1", "2", "3", "4"); |
||||||
|
assertThat(this.conversionService.convert(list, List.class)).isSameAs(list); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertListStringWhenListNumberThenConverts() { |
||||||
|
assertThat(this.conversionService.convert(Lists.list(1, 2, 3, 4), List.class)) |
||||||
|
.isEqualTo(Lists.list("1", "2", "3", "4")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertListStringWhenNotConvertibleThenReturnSingletonList() { |
||||||
|
String string = "not-convertible-list"; |
||||||
|
assertThat(this.conversionService.convert(string, List.class)) |
||||||
|
.isEqualTo(Collections.singletonList(string)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertMapStringObjectWhenNullThenReturnNull() { |
||||||
|
assertThat(this.conversionService.convert(null, Map.class)).isNull(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertMapStringObjectWhenMapStringObjectThenReturnSame() { |
||||||
|
Map<String, Object> mapStringObject = new HashMap<String, Object>() { |
||||||
|
{ |
||||||
|
put("key1", "value1"); |
||||||
|
put("key2", "value2"); |
||||||
|
put("key3", "value3"); |
||||||
|
} |
||||||
|
}; |
||||||
|
assertThat(this.conversionService.convert(mapStringObject, Map.class)).isSameAs(mapStringObject); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertMapStringObjectWhenMapIntegerObjectThenConverts() { |
||||||
|
Map<String, Object> mapStringObject = new HashMap<String, Object>() { |
||||||
|
{ |
||||||
|
put("1", "value1"); |
||||||
|
put("2", "value2"); |
||||||
|
put("3", "value3"); |
||||||
|
} |
||||||
|
}; |
||||||
|
Map<Integer, Object> mapIntegerObject = new HashMap<Integer, Object>() { |
||||||
|
{ |
||||||
|
put(1, "value1"); |
||||||
|
put(2, "value2"); |
||||||
|
put(3, "value3"); |
||||||
|
} |
||||||
|
}; |
||||||
|
assertThat(this.conversionService.convert(mapIntegerObject, Map.class)).isEqualTo(mapStringObject); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertMapStringObjectWhenNotConvertibleThenReturnNull() { |
||||||
|
List<String> notConvertibleList = Lists.list("1", "2", "3", "4"); |
||||||
|
assertThat(this.conversionService.convert(notConvertibleList, Map.class)).isNull(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,170 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2019 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.oauth2.core.converter; |
||||||
|
|
||||||
|
import org.assertj.core.util.Lists; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.core.convert.TypeDescriptor; |
||||||
|
import org.springframework.core.convert.converter.Converter; |
||||||
|
|
||||||
|
import java.net.URL; |
||||||
|
import java.time.Instant; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests for {@link ClaimTypeConverter}. |
||||||
|
* |
||||||
|
* @author Joe Grandja |
||||||
|
* @since 5.2 |
||||||
|
*/ |
||||||
|
public class ClaimTypeConverterTests { |
||||||
|
private static final String STRING_CLAIM = "string-claim"; |
||||||
|
private static final String BOOLEAN_CLAIM = "boolean-claim"; |
||||||
|
private static final String INSTANT_CLAIM = "instant-claim"; |
||||||
|
private static final String URL_CLAIM = "url-claim"; |
||||||
|
private static final String COLLECTION_STRING_CLAIM = "collection-string-claim"; |
||||||
|
private static final String LIST_STRING_CLAIM = "list-string-claim"; |
||||||
|
private static final String MAP_STRING_OBJECT_CLAIM = "map-string-object-claim"; |
||||||
|
private ClaimTypeConverter claimTypeConverter; |
||||||
|
|
||||||
|
@Before |
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public void setup() { |
||||||
|
Converter<Object, ?> stringConverter = getConverter(TypeDescriptor.valueOf(String.class)); |
||||||
|
Converter<Object, ?> booleanConverter = getConverter(TypeDescriptor.valueOf(Boolean.class)); |
||||||
|
Converter<Object, ?> instantConverter = getConverter(TypeDescriptor.valueOf(Instant.class)); |
||||||
|
Converter<Object, ?> urlConverter = getConverter(TypeDescriptor.valueOf(URL.class)); |
||||||
|
Converter<Object, ?> collectionStringConverter = getConverter( |
||||||
|
TypeDescriptor.collection(Collection.class, TypeDescriptor.valueOf(String.class))); |
||||||
|
Converter<Object, ?> listStringConverter = getConverter( |
||||||
|
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); |
||||||
|
Converter<Object, ?> mapStringObjectConverter = getConverter( |
||||||
|
TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Object.class))); |
||||||
|
|
||||||
|
Map<String, Converter<Object, ?>> claimTypeConverters = new HashMap<>(); |
||||||
|
claimTypeConverters.put(STRING_CLAIM, stringConverter); |
||||||
|
claimTypeConverters.put(BOOLEAN_CLAIM, booleanConverter); |
||||||
|
claimTypeConverters.put(INSTANT_CLAIM, instantConverter); |
||||||
|
claimTypeConverters.put(URL_CLAIM, urlConverter); |
||||||
|
claimTypeConverters.put(COLLECTION_STRING_CLAIM, collectionStringConverter); |
||||||
|
claimTypeConverters.put(LIST_STRING_CLAIM, listStringConverter); |
||||||
|
claimTypeConverters.put(MAP_STRING_OBJECT_CLAIM, mapStringObjectConverter); |
||||||
|
this.claimTypeConverter = new ClaimTypeConverter(claimTypeConverters); |
||||||
|
} |
||||||
|
|
||||||
|
private static Converter<Object, ?> getConverter(TypeDescriptor targetDescriptor) { |
||||||
|
final TypeDescriptor sourceDescriptor = TypeDescriptor.valueOf(Object.class); |
||||||
|
return source -> ClaimConversionService.getSharedInstance().convert(source, sourceDescriptor, targetDescriptor); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void constructorWhenConvertersNullThenThrowIllegalArgumentException() { |
||||||
|
assertThatThrownBy(() -> new ClaimTypeConverter(null)) |
||||||
|
.isInstanceOf(IllegalArgumentException.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void constructorWhenConvertersHasNullConverterThenThrowIllegalArgumentException() { |
||||||
|
Map<String, Converter<Object, ?>> claimTypeConverters = new HashMap<>(); |
||||||
|
claimTypeConverters.put("claim1", null); |
||||||
|
assertThatThrownBy(() -> new ClaimTypeConverter(claimTypeConverters)) |
||||||
|
.isInstanceOf(IllegalArgumentException.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertWhenClaimsEmptyThenReturnSame() { |
||||||
|
Map<String, Object> claims = new HashMap<>(); |
||||||
|
assertThat(this.claimTypeConverter.convert(claims)).isSameAs(claims); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertWhenAllClaimsRequireConversionThenConvertAll() throws Exception { |
||||||
|
Instant instant = Instant.now(); |
||||||
|
URL url = new URL("https://localhost"); |
||||||
|
List<Number> listNumber = Lists.list(1, 2, 3, 4); |
||||||
|
List<String> listString = Lists.list("1", "2", "3", "4"); |
||||||
|
Map<Integer, Object> mapIntegerObject = new HashMap<>(); |
||||||
|
mapIntegerObject.put(1, "value1"); |
||||||
|
Map<String, Object> mapStringObject = new HashMap<>(); |
||||||
|
mapStringObject.put("1", "value1"); |
||||||
|
|
||||||
|
Map<String, Object> claims = new HashMap<>(); |
||||||
|
claims.put(STRING_CLAIM, Boolean.TRUE); |
||||||
|
claims.put(BOOLEAN_CLAIM, "true"); |
||||||
|
claims.put(INSTANT_CLAIM, instant.toString()); |
||||||
|
claims.put(URL_CLAIM, url.toExternalForm()); |
||||||
|
claims.put(COLLECTION_STRING_CLAIM, listNumber); |
||||||
|
claims.put(LIST_STRING_CLAIM, listNumber); |
||||||
|
claims.put(MAP_STRING_OBJECT_CLAIM, mapIntegerObject); |
||||||
|
|
||||||
|
claims = this.claimTypeConverter.convert(claims); |
||||||
|
|
||||||
|
assertThat(claims.get(STRING_CLAIM)).isEqualTo("true"); |
||||||
|
assertThat(claims.get(BOOLEAN_CLAIM)).isEqualTo(Boolean.TRUE); |
||||||
|
assertThat(claims.get(INSTANT_CLAIM)).isEqualTo(instant); |
||||||
|
assertThat(claims.get(URL_CLAIM)).isEqualTo(url); |
||||||
|
assertThat(claims.get(COLLECTION_STRING_CLAIM)).isEqualTo(listString); |
||||||
|
assertThat(claims.get(LIST_STRING_CLAIM)).isEqualTo(listString); |
||||||
|
assertThat(claims.get(MAP_STRING_OBJECT_CLAIM)).isEqualTo(mapStringObject); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertWhenNoClaimsRequireConversionThenConvertNone() throws Exception { |
||||||
|
String string = "value"; |
||||||
|
Boolean bool = Boolean.TRUE; |
||||||
|
Instant instant = Instant.now(); |
||||||
|
URL url = new URL("https://localhost"); |
||||||
|
List<String> listString = Lists.list("1", "2", "3", "4"); |
||||||
|
Map<String, Object> mapStringObject = new HashMap<>(); |
||||||
|
mapStringObject.put("1", "value1"); |
||||||
|
|
||||||
|
Map<String, Object> claims = new HashMap<>(); |
||||||
|
claims.put(STRING_CLAIM, string); |
||||||
|
claims.put(BOOLEAN_CLAIM, bool); |
||||||
|
claims.put(INSTANT_CLAIM, instant); |
||||||
|
claims.put(URL_CLAIM, url); |
||||||
|
claims.put(COLLECTION_STRING_CLAIM, listString); |
||||||
|
claims.put(LIST_STRING_CLAIM, listString); |
||||||
|
claims.put(MAP_STRING_OBJECT_CLAIM, mapStringObject); |
||||||
|
|
||||||
|
claims = this.claimTypeConverter.convert(claims); |
||||||
|
|
||||||
|
assertThat(claims.get(STRING_CLAIM)).isSameAs(string); |
||||||
|
assertThat(claims.get(BOOLEAN_CLAIM)).isSameAs(bool); |
||||||
|
assertThat(claims.get(INSTANT_CLAIM)).isSameAs(instant); |
||||||
|
assertThat(claims.get(URL_CLAIM)).isSameAs(url); |
||||||
|
assertThat(claims.get(COLLECTION_STRING_CLAIM)).isSameAs(listString); |
||||||
|
assertThat(claims.get(LIST_STRING_CLAIM)).isSameAs(listString); |
||||||
|
assertThat(claims.get(MAP_STRING_OBJECT_CLAIM)).isSameAs(mapStringObject); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void convertWhenConverterNotAvailableThenDoesNotConvert() { |
||||||
|
Map<String, Object> claims = new HashMap<>(); |
||||||
|
claims.put("claim1", "value1"); |
||||||
|
|
||||||
|
claims = this.claimTypeConverter.convert(claims); |
||||||
|
|
||||||
|
assertThat(claims.get("claim1")).isSameAs("value1"); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue