parent
22c8f63390
commit
1c25fe26c9
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* 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.
|
||||
|
@ -18,12 +18,12 @@ package org.springframework.security.config.annotation.web.configuration;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -40,6 +40,7 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
|
|||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
||||
import org.springframework.security.context.DelegatingApplicationListener;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
|
@ -159,6 +160,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
|||
this.webSecurityConfigurers = webSecurityConfigurers;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BeanFactoryPostProcessor conversionServicePostProcessor() {
|
||||
return new RsaKeyConversionServicePostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
|
||||
ConfigurableListableBeanFactory beanFactory) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* 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.
|
||||
|
@ -20,10 +20,12 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.crypto.RsaKeyConversionServicePostProcessor;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
@ -66,6 +68,11 @@ class WebFluxSecurityConfiguration {
|
|||
return new CsrfRequestDataValueProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static BeanFactoryPostProcessor conversionServicePostProcessor() {
|
||||
return new RsaKeyConversionServicePostProcessor();
|
||||
}
|
||||
|
||||
private List<SecurityWebFilterChain> getSecurityWebFilterChains() {
|
||||
List<SecurityWebFilterChain> result = this.securityWebFilterChains;
|
||||
if (ObjectUtils.isEmpty(result)) {
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* 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.config.crypto;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.converter.RsaKeyConverters;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adds {@link RsaKeyConverters} to the configured {@link ConversionService} or {@link PropertyEditor}s
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
*/
|
||||
public class RsaKeyConversionServicePostProcessor implements BeanFactoryPostProcessor {
|
||||
private static final String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
Assert.notNull(resourceLoader, "resourceLoader cannot be null");
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (hasUserDefinedConversionService(beanFactory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Converter<String, RSAPrivateKey> pkcs8 = pkcs8();
|
||||
Converter<String, RSAPublicKey> x509 = x509();
|
||||
|
||||
ConversionService service = beanFactory.getConversionService();
|
||||
if (service instanceof ConverterRegistry) {
|
||||
ConverterRegistry registry = (ConverterRegistry) service;
|
||||
registry.addConverter(String.class, RSAPrivateKey.class, pkcs8);
|
||||
registry.addConverter(String.class, RSAPublicKey.class, x509);
|
||||
} else {
|
||||
beanFactory.addPropertyEditorRegistrar(registry -> {
|
||||
registry.registerCustomEditor(RSAPublicKey.class, new ConverterPropertyEditorAdapter<>(x509));
|
||||
registry.registerCustomEditor(RSAPrivateKey.class, new ConverterPropertyEditorAdapter<>(pkcs8));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasUserDefinedConversionService(ConfigurableListableBeanFactory beanFactory) {
|
||||
return beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
|
||||
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class);
|
||||
}
|
||||
|
||||
private Converter<String, RSAPrivateKey> pkcs8() {
|
||||
Converter<String, InputStream> pemInputStreamConverter = pemInputStreamConverter();
|
||||
Converter<InputStream, RSAPrivateKey> pkcs8KeyConverter = autoclose(RsaKeyConverters.pkcs8());
|
||||
return pair(pemInputStreamConverter, pkcs8KeyConverter);
|
||||
}
|
||||
|
||||
private Converter<String, RSAPublicKey> x509() {
|
||||
Converter<String, InputStream> pemInputStreamConverter = pemInputStreamConverter();
|
||||
Converter<InputStream, RSAPublicKey> x509KeyConverter = autoclose(RsaKeyConverters.x509());
|
||||
return pair(pemInputStreamConverter, x509KeyConverter);
|
||||
}
|
||||
|
||||
private Converter<String, InputStream> pemInputStreamConverter() {
|
||||
return source -> source.startsWith("-----") ?
|
||||
toInputStream(source) : toInputStream(this.resourceLoader.getResource(source));
|
||||
}
|
||||
|
||||
private InputStream toInputStream(String raw) {
|
||||
return new ByteArrayInputStream(raw.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private InputStream toInputStream(Resource resource) {
|
||||
try {
|
||||
return resource.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Converter<InputStream, T> autoclose(Converter<InputStream, T> inputStreamKeyConverter) {
|
||||
return inputStream -> {
|
||||
try (InputStream is = inputStream) {
|
||||
return inputStreamKeyConverter.convert(is);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private <S, T, I> Converter<S, T> pair(Converter<S, I> one, Converter<I, T> two) {
|
||||
return source -> {
|
||||
I intermediary = one.convert(source);
|
||||
return two.convert(intermediary);
|
||||
};
|
||||
}
|
||||
|
||||
private static class ConverterPropertyEditorAdapter<T> extends PropertyEditorSupport {
|
||||
private final Converter<String, T> converter;
|
||||
|
||||
public ConverterPropertyEditorAdapter(Converter<String, T> converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (StringUtils.hasText(text)) {
|
||||
setValue(this.converter.convert(text));
|
||||
} else {
|
||||
setValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* 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.config.crypto;
|
||||
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
/**
|
||||
* Tests for {@link RsaKeyConversionServicePostProcessor}
|
||||
*/
|
||||
public class RsaKeyConversionServicePostProcessorTests {
|
||||
|
||||
private static final String PKCS8_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV\n" +
|
||||
"HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i\n" +
|
||||
"RpYYZPe2VoO5sumzJt8P6fS80/TAKjhJDAqgZKRJTgGN8KxCM6p/aJli1ZeDBqiV\n" +
|
||||
"v7vJJe+ZgJuPGRS+HMNa/wPxEkqqXsglcJcQV1ZEtfKXSHB7jizKpRL38185SyAC\n" +
|
||||
"pwyjvBu6Cmm1URfhQo88mf239ONh4dZ2HoDfzN1q6Ssu4F4hgutxr9B0DVLDP5u+\n" +
|
||||
"WFrm3nsJ76zf99uJ+ntMUHJ+bY+gOjSlVWIVBIZeAaEGKCNWRk/knjvjbijpvm3U\n" +
|
||||
"acGlgdL3AgMBAAECggEACxxxS7zVyu91qI2s5eSKmAQAXMqgup6+2hUluc47nqUv\n" +
|
||||
"uZz/c/6MPkn2Ryo+65d4IgqmMFjSfm68B/2ER5FTcvoLl1Xo2twrrVpUmcg3BClS\n" +
|
||||
"IZPuExdhVNnxjYKEWwcyZrehyAoR261fDdcFxLRW588efIUC+rPTTRHzAc7sT+Ln\n" +
|
||||
"t/uFeYNWJm3LaegOLoOmlMAhJ5puAWSN1F0FxtRf/RVgzbLA9QC975SKHJsfWCSr\n" +
|
||||
"IZyPsdeaqomKaF65l8nfqlE0Ua2L35gIOGKjUwb7uUE8nI362RWMtYdoi3zDDyoY\n" +
|
||||
"hSFbgjylCHDM0u6iSh6KfqOHtkYyJ8tUYgVWl787wQKBgQDYO3wL7xuDdD101Lyl\n" +
|
||||
"AnaDdFB9fxp83FG1cWr+t7LYm9YxGfEUsKHAJXN6TIayDkOOoVwIl+Gz0T3Z06Bm\n" +
|
||||
"eBGLrB9mrVA7+C7NJwu5gTMlzP6HxUR9zKJIQ/VB1NUGM77LSmvOFbHc9Q0+z8EH\n" +
|
||||
"X5WO516a3Z7lNtZJcCoPOtu2rwKBgQCmbj41Fh+SSEUApCEKms5ETRpe7LXQlJgx\n" +
|
||||
"yW7zcJNNuIb1C3vBLPxjiOTMgYKOeMg5rtHTGLT43URHLh9ArjawasjSAr4AM3J4\n" +
|
||||
"xpoi/sKGDdiKOsuDWIGfzdYL8qyTHSdpZLQsCTMRiRYgAHZFPgNa7SLZRfZicGlr\n" +
|
||||
"GHN1rJW6OQKBgEjiM/upyrJSWeypUDSmUeAZMpA6aWkwsfHgmtnkfUn5rQa74cDB\n" +
|
||||
"kKO9e+D7LmOR3z+SL/1NhGwh2SE07dncGr3jdGodfO/ZxZyszozmeaECKcEFwwJM\n" +
|
||||
"GV8WWPKplGwUwPiwywmZ0mvRxXcoe73KgBS88+xrSwWjqDL0tZiQlEJNAoGATkei\n" +
|
||||
"GMQMG3jEg9Wu+NbxV6zQT3+U0MNjhl9RQU1c63x0dcNt9OFc4NAdlZcAulRTENaK\n" +
|
||||
"OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I\n" +
|
||||
"k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT\n" +
|
||||
"Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3\n" +
|
||||
"EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n" +
|
||||
"yPfcul058SOqhafIZQMEKQ==\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
private static final String X509_PUBLIC_KEY_LOCATION =
|
||||
"classpath:org/springframework/security/config/annotation/web/configuration/simple.pub";
|
||||
|
||||
private final RsaKeyConversionServicePostProcessor postProcessor =
|
||||
new RsaKeyConversionServicePostProcessor();
|
||||
private ConversionService service;
|
||||
|
||||
@Value("classpath:org/springframework/security/config/annotation/web/configuration/simple.pub")
|
||||
RSAPublicKey publicKey;
|
||||
|
||||
@Value("classpath:org/springframework/security/config/annotation/web/configuration/simple.priv")
|
||||
RSAPrivateKey privateKey;
|
||||
|
||||
@Value("custom:simple.pub")
|
||||
RSAPublicKey samePublicKey;
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.setConversionService(new GenericConversionService());
|
||||
this.postProcessor.postProcessBeanFactory(beanFactory);
|
||||
this.service = beanFactory.getConversionService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenUsingConversionServiceForRawKeyThenOk() {
|
||||
RSAPrivateKey key = this.service.convert(PKCS8_PRIVATE_KEY, RSAPrivateKey.class);
|
||||
assertThat(key.getModulus().bitLength()).isEqualTo(2048);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenUsingConversionServiceForClasspathThenOk() {
|
||||
RSAPublicKey key = this.service.convert(X509_PUBLIC_KEY_LOCATION, RSAPublicKey.class);
|
||||
assertThat(key.getModulus().bitLength()).isEqualTo(1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueWhenReferringToClasspathPublicKeyThenConverts() {
|
||||
this.spring.register(CustomResourceLoaderConfig.class, DefaultConfig.class).autowire();
|
||||
assertThat(this.publicKey.getModulus().bitLength()).isEqualTo(1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueWhenReferringToClasspathPrivateKeyThenConverts() {
|
||||
this.spring.register(CustomResourceLoaderConfig.class, DefaultConfig.class).autowire();
|
||||
assertThat(this.privateKey.getModulus().bitLength()).isEqualTo(2048);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueWhenReferringToCustomResourceLoadedPublicKeyThenConverts() {
|
||||
this.spring.register(CustomResourceLoaderConfig.class, DefaultConfig.class).autowire();
|
||||
assertThat(this.samePublicKey.getModulus().bitLength()).isEqualTo(1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueWhenOverridingConversionServiceThenUsed() {
|
||||
assertThatCode(() ->
|
||||
this.spring.register(OverrideConversionServiceConfig.class, DefaultConfig.class).autowire())
|
||||
.hasRootCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultConfig { }
|
||||
|
||||
@Configuration
|
||||
static class CustomResourceLoaderConfig {
|
||||
@Bean
|
||||
BeanFactoryPostProcessor conversionServiceCustomizer() {
|
||||
return beanFactory -> beanFactory.getBean(RsaKeyConversionServicePostProcessor.class)
|
||||
.setResourceLoader(new CustomResourceLoader());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class OverrideConversionServiceConfig {
|
||||
@Bean
|
||||
ConversionService conversionService() {
|
||||
GenericConversionService service = new GenericConversionService();
|
||||
service.addConverter(String.class, RSAPublicKey.class, source -> {
|
||||
throw new IllegalArgumentException("unsupported");
|
||||
});
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomResourceLoader implements ResourceLoader {
|
||||
private final ResourceLoader delegate = new DefaultResourceLoader();
|
||||
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
if (location.startsWith("classpath:")) {
|
||||
return this.delegate.getResource(location);
|
||||
} else if (location.startsWith("custom:")) {
|
||||
String[] parts = location.split(":");
|
||||
return this.delegate.getResource(
|
||||
"classpath:org/springframework/security/config/annotation/web/configuration/" + parts[1]);
|
||||
}
|
||||
throw new IllegalArgumentException("unsupported resource");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return this.delegate.getClassLoader();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ import reactor.core.publisher.Mono;
|
|||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
@ -174,6 +175,16 @@ public class OAuth2ResourceServerSpecTests {
|
|||
.expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer error=\"invalid_token\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenValidUsingPlaceholderThenReturnsOk() {
|
||||
this.spring.register(PlaceholderConfig.class, RootController.class).autowire();
|
||||
|
||||
this.client.get()
|
||||
.headers(headers -> headers.setBearerAuth(this.messageReadToken))
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenCustomDecoderThenAuthenticatesAccordingly() {
|
||||
this.spring.register(CustomDecoderConfig.class, RootController.class).autowire();
|
||||
|
@ -383,6 +394,29 @@ public class OAuth2ResourceServerSpecTests {
|
|||
}
|
||||
}
|
||||
|
||||
@EnableWebFlux
|
||||
@EnableWebFluxSecurity
|
||||
static class PlaceholderConfig {
|
||||
@Value("${classpath:org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests-simple.pub}")
|
||||
RSAPublicKey key;
|
||||
|
||||
@Bean
|
||||
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange()
|
||||
.anyExchange().hasAuthority("SCOPE_message:read")
|
||||
.and()
|
||||
.oauth2ResourceServer()
|
||||
.jwt()
|
||||
.publicKey(this.key);
|
||||
// @formatter:on
|
||||
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebFlux
|
||||
@EnableWebFluxSecurity
|
||||
static class JwkSetUriConfig {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV
|
||||
HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i
|
||||
RpYYZPe2VoO5sumzJt8P6fS80/TAKjhJDAqgZKRJTgGN8KxCM6p/aJli1ZeDBqiV
|
||||
v7vJJe+ZgJuPGRS+HMNa/wPxEkqqXsglcJcQV1ZEtfKXSHB7jizKpRL38185SyAC
|
||||
pwyjvBu6Cmm1URfhQo88mf239ONh4dZ2HoDfzN1q6Ssu4F4hgutxr9B0DVLDP5u+
|
||||
WFrm3nsJ76zf99uJ+ntMUHJ+bY+gOjSlVWIVBIZeAaEGKCNWRk/knjvjbijpvm3U
|
||||
acGlgdL3AgMBAAECggEACxxxS7zVyu91qI2s5eSKmAQAXMqgup6+2hUluc47nqUv
|
||||
uZz/c/6MPkn2Ryo+65d4IgqmMFjSfm68B/2ER5FTcvoLl1Xo2twrrVpUmcg3BClS
|
||||
IZPuExdhVNnxjYKEWwcyZrehyAoR261fDdcFxLRW588efIUC+rPTTRHzAc7sT+Ln
|
||||
t/uFeYNWJm3LaegOLoOmlMAhJ5puAWSN1F0FxtRf/RVgzbLA9QC975SKHJsfWCSr
|
||||
IZyPsdeaqomKaF65l8nfqlE0Ua2L35gIOGKjUwb7uUE8nI362RWMtYdoi3zDDyoY
|
||||
hSFbgjylCHDM0u6iSh6KfqOHtkYyJ8tUYgVWl787wQKBgQDYO3wL7xuDdD101Lyl
|
||||
AnaDdFB9fxp83FG1cWr+t7LYm9YxGfEUsKHAJXN6TIayDkOOoVwIl+Gz0T3Z06Bm
|
||||
eBGLrB9mrVA7+C7NJwu5gTMlzP6HxUR9zKJIQ/VB1NUGM77LSmvOFbHc9Q0+z8EH
|
||||
X5WO516a3Z7lNtZJcCoPOtu2rwKBgQCmbj41Fh+SSEUApCEKms5ETRpe7LXQlJgx
|
||||
yW7zcJNNuIb1C3vBLPxjiOTMgYKOeMg5rtHTGLT43URHLh9ArjawasjSAr4AM3J4
|
||||
xpoi/sKGDdiKOsuDWIGfzdYL8qyTHSdpZLQsCTMRiRYgAHZFPgNa7SLZRfZicGlr
|
||||
GHN1rJW6OQKBgEjiM/upyrJSWeypUDSmUeAZMpA6aWkwsfHgmtnkfUn5rQa74cDB
|
||||
kKO9e+D7LmOR3z+SL/1NhGwh2SE07dncGr3jdGodfO/ZxZyszozmeaECKcEFwwJM
|
||||
GV8WWPKplGwUwPiwywmZ0mvRxXcoe73KgBS88+xrSwWjqDL0tZiQlEJNAoGATkei
|
||||
GMQMG3jEg9Wu+NbxV6zQT3+U0MNjhl9RQU1c63x0dcNt9OFc4NAdlZcAulRTENaK
|
||||
OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I
|
||||
k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT
|
||||
Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3
|
||||
EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo
|
||||
yPfcul058SOqhafIZQMEKQ==
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
|
||||
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
|
||||
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
|
||||
o2kQ+X5xK9cipRgEKwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0IUjrPZDz+3z0UE4ppcKU36v7hnh8FJjhu3lbJYj0qj9eZiwEJxi9HHUfSK1DhUQG7mJBbYTK1tPYCgre5EkfKh+64VhYUa+vz17zYCmuB8fFj4XHE3MLkWIG+AUn8hNbPzYYmiBTjfGnMKxLHjsbdTiF4mtn+85w366916R6midnAuiPD4HjZaZ1PAsuY60gr8bhMEDtJ8unz81hoQrozpBZJ6r8aR1PrsWb1OqPMloK9kAIutJNvWYKacp8WYAp2WWy72PxQ7Fb0eIA1br3A5dnp+Cln6JROJcZUIRJ+QvS6QONWeS2407uQmS+i+lybsqaH0ldYC7NBEBA5inPQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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.converter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Used for creating {@link java.security.Key} converter instances
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
*/
|
||||
public class RsaKeyConverters {
|
||||
private static final String DASHES = "-----";
|
||||
private static final String PKCS8_PEM_HEADER = DASHES + "BEGIN PRIVATE KEY" + DASHES;
|
||||
private static final String PKCS8_PEM_FOOTER = DASHES + "END PRIVATE KEY" + DASHES;
|
||||
private static final String X509_PEM_HEADER = DASHES + "BEGIN PUBLIC KEY" + DASHES;
|
||||
private static final String X509_PEM_FOOTER = DASHES + "END PUBLIC KEY" + DASHES;
|
||||
|
||||
/**
|
||||
* Construct a {@link Converter} for converting a PEM-encoded PKCS#8 RSA Private Key
|
||||
* into a {@link RSAPrivateKey}.
|
||||
*
|
||||
* Note that keys are often formatted in PKCS#1 and this can easily be identified by the header.
|
||||
* If the key file begins with "-----BEGIN RSA PRIVATE KEY-----", then it is PKCS#1. If it is
|
||||
* PKCS#8 formatted, then it begins with "-----BEGIN PRIVATE KEY-----".
|
||||
*
|
||||
* This converter does not close the {@link InputStream} in order to avoid making non-portable
|
||||
* assumptions about the streams' origin and further use.
|
||||
*
|
||||
* @return A {@link Converter} that can read a PEM-encoded PKCS#8 RSA Private Key and return a
|
||||
* {@link RSAPrivateKey}.
|
||||
*/
|
||||
public static Converter<InputStream, RSAPrivateKey> pkcs8() {
|
||||
KeyFactory keyFactory = rsaFactory();
|
||||
return source -> {
|
||||
List<String> lines = readAllLines(source);
|
||||
Assert.isTrue(!lines.isEmpty() && lines.get(0).startsWith(PKCS8_PEM_HEADER),
|
||||
"Key is not in PEM-encoded PKCS#8 format, " +
|
||||
"please check that the header begins with -----" + PKCS8_PEM_HEADER + "-----");
|
||||
String base64Encoded = lines.stream()
|
||||
.filter(RsaKeyConverters::isNotPkcs8Wrapper)
|
||||
.collect(Collectors.joining());
|
||||
byte[] pkcs8 = Base64.getDecoder().decode(base64Encoded);
|
||||
|
||||
try {
|
||||
return (RSAPrivateKey) keyFactory.generatePrivate(
|
||||
new PKCS8EncodedKeySpec(pkcs8));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link Converter} for converting a PEM-encoded X.509 RSA Public Key
|
||||
* into a {@link RSAPublicKey}.
|
||||
*
|
||||
* This converter does not close the {@link InputStream} in order to avoid making non-portable
|
||||
* assumptions about the streams' origin and further use.
|
||||
*
|
||||
* @return A {@link Converter} that can read a PEM-encoded X.509 RSA Public Key and return a
|
||||
* {@link RSAPublicKey}.
|
||||
*/
|
||||
public static Converter<InputStream, RSAPublicKey> x509() {
|
||||
KeyFactory keyFactory = rsaFactory();
|
||||
return source -> {
|
||||
List<String> lines = readAllLines(source);
|
||||
Assert.isTrue(!lines.isEmpty() && lines.get(0).startsWith(X509_PEM_HEADER),
|
||||
"Key is not in PEM-encoded X.509 format, " +
|
||||
"please check that the header begins with -----" + X509_PEM_HEADER + "-----");
|
||||
String base64Encoded = lines.stream()
|
||||
.filter(RsaKeyConverters::isNotX509Wrapper)
|
||||
.collect(Collectors.joining());
|
||||
byte[] x509 = Base64.getDecoder().decode(base64Encoded);
|
||||
|
||||
try {
|
||||
return (RSAPublicKey) keyFactory.generatePublic(
|
||||
new X509EncodedKeySpec(x509));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<String> readAllLines(InputStream source) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(source));
|
||||
return reader.lines().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static KeyFactory rsaFactory() {
|
||||
try {
|
||||
return KeyFactory.getInstance("RSA");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNotPkcs8Wrapper(String line) {
|
||||
return !PKCS8_PEM_HEADER.equals(line) && !PKCS8_PEM_FOOTER.equals(line);
|
||||
}
|
||||
|
||||
private static boolean isNotX509Wrapper(String line) {
|
||||
return !X509_PEM_HEADER.equals(line) && !X509_PEM_FOOTER.equals(line);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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.converter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.interfaces.RSAPrivateCrtKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.AssertionsForClassTypes;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Tests for {@link RsaKeyConverters}
|
||||
*/
|
||||
public class RsaKeyConvertersTest {
|
||||
private static final String PKCS8_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV\n" +
|
||||
"HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i\n" +
|
||||
"RpYYZPe2VoO5sumzJt8P6fS80/TAKjhJDAqgZKRJTgGN8KxCM6p/aJli1ZeDBqiV\n" +
|
||||
"v7vJJe+ZgJuPGRS+HMNa/wPxEkqqXsglcJcQV1ZEtfKXSHB7jizKpRL38185SyAC\n" +
|
||||
"pwyjvBu6Cmm1URfhQo88mf239ONh4dZ2HoDfzN1q6Ssu4F4hgutxr9B0DVLDP5u+\n" +
|
||||
"WFrm3nsJ76zf99uJ+ntMUHJ+bY+gOjSlVWIVBIZeAaEGKCNWRk/knjvjbijpvm3U\n" +
|
||||
"acGlgdL3AgMBAAECggEACxxxS7zVyu91qI2s5eSKmAQAXMqgup6+2hUluc47nqUv\n" +
|
||||
"uZz/c/6MPkn2Ryo+65d4IgqmMFjSfm68B/2ER5FTcvoLl1Xo2twrrVpUmcg3BClS\n" +
|
||||
"IZPuExdhVNnxjYKEWwcyZrehyAoR261fDdcFxLRW588efIUC+rPTTRHzAc7sT+Ln\n" +
|
||||
"t/uFeYNWJm3LaegOLoOmlMAhJ5puAWSN1F0FxtRf/RVgzbLA9QC975SKHJsfWCSr\n" +
|
||||
"IZyPsdeaqomKaF65l8nfqlE0Ua2L35gIOGKjUwb7uUE8nI362RWMtYdoi3zDDyoY\n" +
|
||||
"hSFbgjylCHDM0u6iSh6KfqOHtkYyJ8tUYgVWl787wQKBgQDYO3wL7xuDdD101Lyl\n" +
|
||||
"AnaDdFB9fxp83FG1cWr+t7LYm9YxGfEUsKHAJXN6TIayDkOOoVwIl+Gz0T3Z06Bm\n" +
|
||||
"eBGLrB9mrVA7+C7NJwu5gTMlzP6HxUR9zKJIQ/VB1NUGM77LSmvOFbHc9Q0+z8EH\n" +
|
||||
"X5WO516a3Z7lNtZJcCoPOtu2rwKBgQCmbj41Fh+SSEUApCEKms5ETRpe7LXQlJgx\n" +
|
||||
"yW7zcJNNuIb1C3vBLPxjiOTMgYKOeMg5rtHTGLT43URHLh9ArjawasjSAr4AM3J4\n" +
|
||||
"xpoi/sKGDdiKOsuDWIGfzdYL8qyTHSdpZLQsCTMRiRYgAHZFPgNa7SLZRfZicGlr\n" +
|
||||
"GHN1rJW6OQKBgEjiM/upyrJSWeypUDSmUeAZMpA6aWkwsfHgmtnkfUn5rQa74cDB\n" +
|
||||
"kKO9e+D7LmOR3z+SL/1NhGwh2SE07dncGr3jdGodfO/ZxZyszozmeaECKcEFwwJM\n" +
|
||||
"GV8WWPKplGwUwPiwywmZ0mvRxXcoe73KgBS88+xrSwWjqDL0tZiQlEJNAoGATkei\n" +
|
||||
"GMQMG3jEg9Wu+NbxV6zQT3+U0MNjhl9RQU1c63x0dcNt9OFc4NAdlZcAulRTENaK\n" +
|
||||
"OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I\n" +
|
||||
"k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT\n" +
|
||||
"Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3\n" +
|
||||
"EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n" +
|
||||
"yPfcul058SOqhafIZQMEKQ==\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
|
||||
private static final String PKCS1_PRIVATE_KEY =
|
||||
"-----BEGIN RSA PRIVATE KEY-----\n" +
|
||||
"MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw\n" +
|
||||
"33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW\n" +
|
||||
"+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB\n" +
|
||||
"AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS\n" +
|
||||
"3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp\n" +
|
||||
"uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE\n" +
|
||||
"2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0\n" +
|
||||
"GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K\n" +
|
||||
"Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY\n" +
|
||||
"6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5\n" +
|
||||
"fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523\n" +
|
||||
"Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP\n" +
|
||||
"FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==\n" +
|
||||
"-----END RSA PRIVATE KEY-----";
|
||||
|
||||
private static final String X509_PUBLIC_KEY =
|
||||
"-----BEGIN PUBLIC KEY-----\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n" +
|
||||
"UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n" +
|
||||
"HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n" +
|
||||
"o2kQ+X5xK9cipRgEKwIDAQAB\n" +
|
||||
"-----END PUBLIC KEY-----";
|
||||
|
||||
private static final String MALFORMED_X509_KEY = "malformed";
|
||||
|
||||
private final Converter<InputStream, RSAPublicKey> x509 = RsaKeyConverters.x509();
|
||||
private final Converter<InputStream, RSAPrivateKey> pkcs8 = RsaKeyConverters.pkcs8();
|
||||
|
||||
@Test
|
||||
public void pkcs8WhenConvertingPkcs8PrivateKeyThenOk() {
|
||||
RSAPrivateKey key = this.pkcs8.convert(toInputStream(PKCS8_PRIVATE_KEY));
|
||||
Assertions.assertThat(key).isInstanceOf(RSAPrivateCrtKey.class);
|
||||
Assertions.assertThat(key.getModulus().bitLength()).isEqualTo(2048);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pkcs8WhenConvertingPkcs1PrivateKeyThenIllegalArgumentException() {
|
||||
AssertionsForClassTypes.assertThatCode(() -> this.pkcs8.convert(toInputStream(PKCS1_PRIVATE_KEY)))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void x509WhenConverteringX509PublicKeyThenOk() {
|
||||
RSAPublicKey key = this.x509.convert(toInputStream(X509_PUBLIC_KEY));
|
||||
Assertions.assertThat(key.getModulus().bitLength()).isEqualTo(1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void x509WhenConvertingDerEncodedX509PublicKeyThenIllegalArgumentException() {
|
||||
AssertionsForClassTypes.assertThatCode(() -> this.x509.convert(toInputStream(MALFORMED_X509_KEY)))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
private static InputStream toInputStream(String string) {
|
||||
return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue