Rework security autoconfiguration
This commit combines security autoconfigurations for management endpoints and the rest of the application. By default, if Spring Security is on the classpath, it turns on @EnableWebSecurity. In the presence of another WebSecurityConfigurerAdapter this backs off completely. A default AuthenticationManager is also provided with a user and generated password. This can be turned off by specifying a bean of type AuthenticationManager, AuthenticationProvider or UserDetailsService. Closes gh-7958
This commit is contained in:
parent
f60ad0df74
commit
e08ddbf838
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.actuate.autoconfigure.endpoint;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
|
||||
/**
|
||||
* {@link EndpointPathResolver} implementation for resolving
|
||||
* actuator endpoint paths based on the endpoint id and management.context-path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class ManagementEndpointPathResolver implements EndpointPathResolver {
|
||||
|
||||
private final String contextPath;
|
||||
|
||||
public ManagementEndpointPathResolver(ManagementServerProperties properties) {
|
||||
this.contextPath = properties.getContextPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolvePath(String endpointId) {
|
||||
return this.contextPath + "/" + endpointId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -16,340 +16,32 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.security;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ManagementContextResolver;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ManagementEndpointPathResolver;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.security.AuthenticationManagerConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.IgnoredRequestCustomizer;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityPrerequisite;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.endpoint.EndpointInfo;
|
||||
import org.springframework.boot.endpoint.web.WebEndpointOperation;
|
||||
import org.springframework.boot.endpoint.web.mvc.WebEndpointServletHandlerMapping;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for security of framework endpoints.
|
||||
* Many aspects of the behavior can be controller with {@link ManagementServerProperties}
|
||||
* via externalized application properties (or via an bean definition of that type to set
|
||||
* the defaults)..
|
||||
* Security configuration for management endpoints.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class })
|
||||
@AutoConfigureAfter(SecurityAutoConfiguration.class)
|
||||
@AutoConfigureBefore(FallbackWebSecurityAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(ManagementServerProperties.class)
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
public class ManagementWebSecurityAutoConfiguration {
|
||||
|
||||
private static final String[] NO_PATHS = new String[0];
|
||||
|
||||
private static final RequestMatcher MATCH_NONE = new NegatedRequestMatcher(
|
||||
AnyRequestMatcher.INSTANCE);
|
||||
|
||||
@Bean
|
||||
public IgnoredRequestCustomizer managementIgnoredRequestCustomizer(
|
||||
ManagementServerProperties management,
|
||||
ObjectProvider<ManagementContextResolver> contextResolver) {
|
||||
return new ManagementIgnoredRequestCustomizer(management,
|
||||
contextResolver.getIfAvailable());
|
||||
}
|
||||
|
||||
private class ManagementIgnoredRequestCustomizer implements IgnoredRequestCustomizer {
|
||||
|
||||
private final ManagementServerProperties management;
|
||||
|
||||
private final ManagementContextResolver contextResolver;
|
||||
|
||||
ManagementIgnoredRequestCustomizer(ManagementServerProperties management,
|
||||
ManagementContextResolver contextResolver) {
|
||||
this.management = management;
|
||||
this.contextResolver = contextResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(IgnoredRequestConfigurer configurer) {
|
||||
if (!this.management.getSecurity().isEnabled()) {
|
||||
RequestMatcher requestMatcher = LazyEndpointPathRequestMatcher
|
||||
.getRequestMatcher(this.contextResolver);
|
||||
configurer.requestMatchers(requestMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class ManagementSecurityPropertiesConfiguration
|
||||
implements SecurityPrerequisite {
|
||||
|
||||
private final SecurityProperties securityProperties;
|
||||
|
||||
private final ManagementServerProperties managementServerProperties;
|
||||
|
||||
public ManagementSecurityPropertiesConfiguration(
|
||||
ObjectProvider<SecurityProperties> securityProperties,
|
||||
ObjectProvider<ManagementServerProperties> managementServerProperties) {
|
||||
this.securityProperties = securityProperties.getIfAvailable();
|
||||
this.managementServerProperties = managementServerProperties.getIfAvailable();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (this.managementServerProperties != null
|
||||
&& this.securityProperties != null) {
|
||||
this.securityProperties.getUser().getRole()
|
||||
.addAll(this.managementServerProperties.getSecurity().getRoles());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(WebSecurityConfiguration.class)
|
||||
@Conditional(WebSecurityEnablerCondition.class)
|
||||
@EnableWebSecurity
|
||||
protected static class WebSecurityEnabler extends AuthenticationManagerConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSecurityEnabler condition.
|
||||
*/
|
||||
static class WebSecurityEnablerCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
String managementEnabled = context.getEnvironment()
|
||||
.getProperty("management.security.enabled", "true");
|
||||
String basicEnabled = context.getEnvironment()
|
||||
.getProperty("security.basic.enabled", "true");
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("WebSecurityEnabled");
|
||||
if ("true".equalsIgnoreCase(managementEnabled)
|
||||
&& !"true".equalsIgnoreCase(basicEnabled)) {
|
||||
return ConditionOutcome.match(message.because("security enabled"));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.because("security disabled"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean({ ManagementWebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnProperty(prefix = "management.security", name = "enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
@Order(ManagementServerProperties.BASIC_AUTH_ORDER)
|
||||
protected static class ManagementWebSecurityConfigurerAdapter
|
||||
extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final SecurityProperties security;
|
||||
|
||||
private final ManagementServerProperties management;
|
||||
|
||||
private final ManagementContextResolver contextResolver;
|
||||
|
||||
public ManagementWebSecurityConfigurerAdapter(SecurityProperties security,
|
||||
ManagementServerProperties management,
|
||||
ObjectProvider<ManagementContextResolver> contextResolver) {
|
||||
this.security = security;
|
||||
this.management = management;
|
||||
this.contextResolver = contextResolver.getIfAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// secure endpoints
|
||||
RequestMatcher matcher = getRequestMatcher();
|
||||
if (matcher != null) {
|
||||
// Always protect them if present
|
||||
if (this.security.isRequireSsl()) {
|
||||
http.requiresChannel().anyRequest().requiresSecure();
|
||||
}
|
||||
AuthenticationEntryPoint entryPoint = entryPoint();
|
||||
http.exceptionHandling().authenticationEntryPoint(entryPoint);
|
||||
// Match all the requests for actuator endpoints ...
|
||||
http.requestMatcher(matcher).authorizeRequests().anyRequest()
|
||||
.authenticated();
|
||||
http.httpBasic().authenticationEntryPoint(entryPoint).and().cors();
|
||||
// No cookies for management endpoints by default
|
||||
http.csrf().disable();
|
||||
http.sessionManagement()
|
||||
.sessionCreationPolicy(asSpringSecuritySessionCreationPolicy(
|
||||
this.management.getSecurity().getSessions()));
|
||||
SpringBootWebSecurityConfiguration.configureHeaders(http.headers(),
|
||||
this.security.getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
private SessionCreationPolicy asSpringSecuritySessionCreationPolicy(
|
||||
Enum<?> value) {
|
||||
if (value == null) {
|
||||
return SessionCreationPolicy.STATELESS;
|
||||
}
|
||||
return SessionCreationPolicy.valueOf(value.name());
|
||||
}
|
||||
|
||||
private RequestMatcher getRequestMatcher() {
|
||||
if (this.management.getSecurity().isEnabled()) {
|
||||
return LazyEndpointPathRequestMatcher
|
||||
.getRequestMatcher(this.contextResolver);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private AuthenticationEntryPoint entryPoint() {
|
||||
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
|
||||
entryPoint.setRealmName(this.security.getBasic().getRealm());
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class EndpointPaths {
|
||||
|
||||
public String[] getPaths(
|
||||
WebEndpointServletHandlerMapping endpointHandlerMapping) {
|
||||
if (endpointHandlerMapping == null) {
|
||||
return NO_PATHS;
|
||||
}
|
||||
Collection<EndpointInfo<WebEndpointOperation>> endpoints = endpointHandlerMapping
|
||||
.getEndpoints();
|
||||
Set<String> paths = new LinkedHashSet<>(endpoints.size());
|
||||
for (EndpointInfo<WebEndpointOperation> endpoint : endpoints) {
|
||||
String path = endpointHandlerMapping.getEndpointPath() + "/"
|
||||
+ endpoint.getId();
|
||||
paths.add(path);
|
||||
paths.add(path + "/**");
|
||||
// Add Spring MVC-generated additional paths
|
||||
paths.add(path + ".*");
|
||||
paths.add(path + "/");
|
||||
}
|
||||
return paths.toArray(new String[paths.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class LazyEndpointPathRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final EndpointPaths endpointPaths;
|
||||
|
||||
private final ManagementContextResolver contextResolver;
|
||||
|
||||
private RequestMatcher delegate;
|
||||
|
||||
public static RequestMatcher getRequestMatcher(
|
||||
ManagementContextResolver contextResolver) {
|
||||
if (contextResolver == null) {
|
||||
return null;
|
||||
}
|
||||
ManagementServerProperties management = contextResolver
|
||||
.getApplicationContext().getBean(ManagementServerProperties.class);
|
||||
ServerProperties server = contextResolver.getApplicationContext()
|
||||
.getBean(ServerProperties.class);
|
||||
String path = management.getContextPath();
|
||||
if (StringUtils.hasText(path)) {
|
||||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(
|
||||
server.getServlet().getPath(path) + "/**");
|
||||
return matcher;
|
||||
}
|
||||
// Match all endpoint paths
|
||||
return new LazyEndpointPathRequestMatcher(contextResolver,
|
||||
new EndpointPaths());
|
||||
}
|
||||
|
||||
LazyEndpointPathRequestMatcher(ManagementContextResolver contextResolver,
|
||||
EndpointPaths endpointPaths) {
|
||||
this.contextResolver = contextResolver;
|
||||
this.endpointPaths = endpointPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = createDelegate();
|
||||
}
|
||||
return this.delegate.matches(request);
|
||||
}
|
||||
|
||||
private RequestMatcher createDelegate() {
|
||||
ServerProperties server = this.contextResolver.getApplicationContext()
|
||||
.getBean(ServerProperties.class);
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
WebEndpointServletHandlerMapping endpointHandlerMapping = getRequiredEndpointHandlerMapping();
|
||||
for (String path : this.endpointPaths.getPaths(endpointHandlerMapping)) {
|
||||
matchers.add(
|
||||
new AntPathRequestMatcher(server.getServlet().getPath(path)));
|
||||
}
|
||||
return (matchers.isEmpty() ? MATCH_NONE : new OrRequestMatcher(matchers));
|
||||
}
|
||||
|
||||
private WebEndpointServletHandlerMapping getRequiredEndpointHandlerMapping() {
|
||||
WebEndpointServletHandlerMapping endpointHandlerMapping = null;
|
||||
ApplicationContext context = this.contextResolver.getApplicationContext();
|
||||
if (context.getBeanNamesForType(
|
||||
WebEndpointServletHandlerMapping.class).length > 0) {
|
||||
endpointHandlerMapping = context
|
||||
.getBean(WebEndpointServletHandlerMapping.class);
|
||||
}
|
||||
if (endpointHandlerMapping == null) {
|
||||
// Maybe there are actually no endpoints (e.g. management.port=-1)
|
||||
endpointHandlerMapping = new WebEndpointServletHandlerMapping("",
|
||||
Collections.emptySet());
|
||||
}
|
||||
return endpointHandlerMapping;
|
||||
}
|
||||
|
||||
public EndpointPathResolver managementEndpointPathResolver(ManagementServerProperties properties) {
|
||||
return new ManagementEndpointPathResolver(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.actuate.autoconfigure.endpoint;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ManagementEndpointPathResolver}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class ManagementEndpointPathResolverTests {
|
||||
|
||||
private ManagementEndpointPathResolver resolver;
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ManagementServerProperties properties = new ManagementServerProperties();
|
||||
properties.setContextPath("/test");
|
||||
this.resolver = new ManagementEndpointPathResolver(properties);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveShouldReturnPathBasedOnContextPath() throws Exception {
|
||||
String path = this.resolver.resolvePath("my-id");
|
||||
assertThat(path.equals("/test/my-id"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.actuate.autoconfigure.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.ServletEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.security.ManagementWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ManagementWebSecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ManagementWebSecurityAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfiguration() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, ServletEndpointAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class);
|
||||
TestPropertyValues.of("security.basic.enabled:false").applyTo(this.context);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
|
||||
FilterChainProxy filterChainProxy = this.context.getBean(FilterChainProxy.class);
|
||||
// 1 for static resources, one for management endpoints and one for the rest
|
||||
assertThat(filterChainProxy.getFilterChains()).hasSize(3);
|
||||
assertThat(filterChainProxy.getFilters("/application/beans")).isNotEmpty();
|
||||
assertThat(filterChainProxy.getFilters("/application/beans/")).isNotEmpty();
|
||||
assertThat(filterChainProxy.getFilters("/application/beans.foo")).isNotEmpty();
|
||||
assertThat(filterChainProxy.getFilters("/application/beans/foo/bar"))
|
||||
.isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathNormalization() throws Exception {
|
||||
String path = "admin/./error";
|
||||
assertThat(StringUtils.cleanPath(path)).isEqualTo("admin/error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationWithExtraRole() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(WebConfiguration.class);
|
||||
this.context.refresh();
|
||||
UserDetails user = getUser();
|
||||
ArrayList<GrantedAuthority> authorities = new ArrayList<>(user.getAuthorities());
|
||||
assertThat(authorities).containsAll(AuthorityUtils
|
||||
.commaSeparatedStringToAuthorityList("ROLE_USER,ROLE_ACTUATOR"));
|
||||
}
|
||||
|
||||
private UserDetails getUser() {
|
||||
ProviderManager parent = (ProviderManager) this.context
|
||||
.getBean(AuthenticationManager.class);
|
||||
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) parent
|
||||
.getProviders().get(0);
|
||||
UserDetailsService service = (UserDetailsService) ReflectionTestUtils
|
||||
.getField(provider, "userDetailsService");
|
||||
UserDetails user = service.loadUserByUsername("user");
|
||||
return user;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableIgnoredStaticApplicationPaths() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
TestPropertyValues.of("security.ignored:none").applyTo(this.context);
|
||||
this.context.refresh();
|
||||
// Just the application and management endpoints now
|
||||
assertThat(this.context.getBean(FilterChainProxy.class).getFilterChains())
|
||||
.hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableBasicAuthOnApplicationPaths() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(WebConfiguration.class);
|
||||
TestPropertyValues.of("security.basic.enabled:false").applyTo(this.context);
|
||||
this.context.refresh();
|
||||
// Just the management endpoints (one filter) and ignores now plus the backup
|
||||
// filter on app endpoints
|
||||
assertThat(this.context.getBean(FilterChainProxy.class).getFilterChains())
|
||||
.hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideAuthenticationManager() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(TestConfiguration.class, SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(AuthenticationManager.class)).isEqualTo(
|
||||
this.context.getBean(TestConfiguration.class).authenticationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecurityPropertiesNotAvailable() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(TestConfiguration.class, SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(AuthenticationManager.class)).isEqualTo(
|
||||
this.context.getBean(TestConfiguration.class).authenticationManager);
|
||||
}
|
||||
|
||||
// gh-2466
|
||||
@Test
|
||||
public void realmSameForManagement() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(AuthenticationConfig.class, SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, ServletEndpointAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
|
||||
AuditAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
|
||||
Filter filter = this.context.getBean("springSecurityFilterChain", Filter.class);
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.addFilters(filter).build();
|
||||
|
||||
// no user (Main)
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/home"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(springAuthenticateRealmHeader());
|
||||
|
||||
// invalid user (Main)
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.get("/home").header("authorization", "Basic xxx"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(springAuthenticateRealmHeader());
|
||||
|
||||
// no user (Management)
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/beans"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(springAuthenticateRealmHeader());
|
||||
|
||||
// invalid user (Management)
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.get("/beans").header("authorization", "Basic xxx"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(springAuthenticateRealmHeader());
|
||||
}
|
||||
|
||||
private ResultMatcher springAuthenticateRealmHeader() {
|
||||
return MockMvcResultMatchers.header().string("www-authenticate",
|
||||
Matchers.containsString("realm=\"Spring\""));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ImportAutoConfiguration({ SecurityAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, ServletEndpointAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, AuditAutoConfiguration.class,
|
||||
FallbackWebSecurityAutoConfiguration.class })
|
||||
static class WebConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@EnableGlobalAuthentication
|
||||
@Configuration
|
||||
static class AuthenticationConfig {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password")
|
||||
.roles("USER");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestConfiguration {
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager myAuthenticationManager() {
|
||||
this.authenticationManager = (
|
||||
authentication) -> new TestingAuthenticationToken("foo", "bar");
|
||||
return this.authenticationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,6 +35,8 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
|
@ -194,4 +196,13 @@ public class MvcEndpointCorsIntegrationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.cors();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfigurati
|
|||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.EndpointInfrastructureAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.ServletEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.security.ManagementWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
|
||||
|
|
@ -36,6 +35,7 @@ import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoC
|
|||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.test.context.TestSecurityContextHolder;
|
||||
|
|
@ -69,7 +69,8 @@ public class MvcEndpointIntegrationTests {
|
|||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/application/beans")).andExpect(status().isUnauthorized());
|
||||
mockMvc.perform(get("/application/beans")
|
||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -79,7 +80,8 @@ public class MvcEndpointIntegrationTests {
|
|||
TestPropertyValues.of("management.context-path:/management")
|
||||
.applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/management/beans")).andExpect(status().isUnauthorized());
|
||||
mockMvc.perform(get("/management/beans")
|
||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -89,31 +91,13 @@ public class MvcEndpointIntegrationTests {
|
|||
new TestingAuthenticationToken("user", "N/A", "ROLE_ACTUATOR"));
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
TestPropertyValues.of("management.context-path:/management")
|
||||
TestPropertyValues.of("management.context-path:/management",
|
||||
"endpoints.all.web.enabled=true")
|
||||
.applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/management/beans")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointSecurityCanBeDisabledWithCustomContextPath() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
TestPropertyValues.of("management.context-path:/management",
|
||||
"management.security.enabled:false").applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/management/beans")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointSecurityCanBeDisabled() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
TestPropertyValues.of("management.security.enabled:false").applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/application/beans")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
private MockMvc createSecureMockMvc() {
|
||||
return doCreateMockMvc(springSecurity());
|
||||
}
|
||||
|
|
@ -153,8 +137,7 @@ public class MvcEndpointIntegrationTests {
|
|||
}
|
||||
|
||||
@Import(DefaultConfiguration.class)
|
||||
@ImportAutoConfiguration({ SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class })
|
||||
@ImportAutoConfiguration({ SecurityAutoConfiguration.class})
|
||||
static class SecureConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.actuate.endpoint.mvc;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.EndpointInfrastructureAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.infrastructure.ServletEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.HealthWebEndpointExtension;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicatorFactory;
|
||||
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions;
|
||||
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Integration tests for the health endpoint when Spring Security is not available.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("spring-security-*.jar")
|
||||
public class NoSpringSecurityHealthMvcEndpointIntegrationTests {
|
||||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthDetailPresent() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(TestConfiguration.class);
|
||||
TestPropertyValues.of("management.security.enabled:false").applyTo(this.context);
|
||||
this.context.refresh();
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
|
||||
mockMvc.perform(get("/application/health")).andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString(
|
||||
"\"status\":\"UP\",\"test\":{\"status\":\"UP\",\"hello\":\"world\"}")));
|
||||
}
|
||||
|
||||
@ImportAutoConfiguration({ JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class,
|
||||
EndpointInfrastructureAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class,
|
||||
ServletEndpointAutoConfiguration.class })
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public HealthIndicator testHealthIndicator() {
|
||||
return () -> Health.up().withDetail("hello", "world").build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthEndpoint healthEndpoint(
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
return new HealthEndpoint(new HealthIndicatorFactory().createHealthIndicator(
|
||||
new OrderedHealthAggregator(), healthIndicators));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthWebEndpointExtension healthWebEndpointExtension(
|
||||
HealthEndpoint delegate) {
|
||||
return new HealthWebEndpointExtension(delegate, new HealthStatusHttpMapper());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAuthorizeMode;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
|
@ -79,7 +78,6 @@ public class H2ConsoleAutoConfiguration {
|
|||
@Configuration
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnBean(ObjectPostProcessor.class)
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
|
||||
static class H2ConsoleSecurityConfiguration {
|
||||
|
||||
|
|
@ -95,9 +93,6 @@ public class H2ConsoleAutoConfiguration {
|
|||
@Autowired
|
||||
private H2ConsoleProperties console;
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
String path = this.console.getPath();
|
||||
|
|
@ -106,14 +101,7 @@ public class H2ConsoleAutoConfiguration {
|
|||
h2Console.csrf().disable();
|
||||
h2Console.httpBasic();
|
||||
h2Console.headers().frameOptions().sameOrigin();
|
||||
String[] roles = this.security.getUser().getRole().toArray(new String[0]);
|
||||
SecurityAuthorizeMode mode = this.security.getBasic().getAuthorizeMode();
|
||||
if (mode == null || mode == SecurityAuthorizeMode.ROLE) {
|
||||
http.authorizeRequests().anyRequest().hasAnyRole(roles);
|
||||
}
|
||||
else if (mode == SecurityAuthorizeMode.AUTHENTICATED) {
|
||||
http.authorizeRequests().anyRequest().authenticated();
|
||||
}
|
||||
http.authorizeRequests().anyRequest().authenticated();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@
|
|||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -29,7 +28,6 @@ import org.springframework.beans.factory.SmartInitializingSingleton;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
|
@ -47,13 +45,13 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
|||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Configuration for a Spring Security in-memory {@link AuthenticationManager}. Can be
|
||||
* disabled by providing a bean of type AuthenticationManager, or by autowiring an
|
||||
* {@link AuthenticationManagerBuilder} into a method in one of your configuration
|
||||
* classes. The value provided by this configuration will become the "global"
|
||||
* disabled by providing a bean of type {@link AuthenticationManager}, {@link AuthenticationProvider}
|
||||
* or {@link UserDetailsService}. The value provided by this configuration will become the "global"
|
||||
* authentication manager (from Spring Security), or the parent of the global instance.
|
||||
* Thus it acts as a fallback when no others are provided, is used by method security if
|
||||
* enabled, and as a parent authentication manager for "local" authentication managers in
|
||||
|
|
@ -61,10 +59,12 @@ import org.springframework.util.ReflectionUtils;
|
|||
*
|
||||
* @author Dave Syer
|
||||
* @author Rob Winch
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnBean(ObjectPostProcessor.class)
|
||||
@ConditionalOnMissingBean({ AuthenticationManager.class })
|
||||
@ConditionalOnMissingBean({ AuthenticationManager.class,
|
||||
AuthenticationProvider.class, UserDetailsService.class})
|
||||
@Order(0)
|
||||
public class AuthenticationManagerConfiguration {
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ public class AuthenticationManagerConfiguration {
|
|||
* {@link GlobalAuthenticationConfigurerAdapter#init(AuthenticationManagerBuilder)}
|
||||
* exists that adds a {@link SecurityConfigurer} to the
|
||||
* {@link AuthenticationManagerBuilder}.</li>
|
||||
* <li>{@link AuthenticationManagerConfiguration#init(AuthenticationManagerBuilder)}
|
||||
* <li>{@link AuthenticationManagerConfiguration}
|
||||
* adds {@link SpringBootAuthenticationConfigurerAdapter} so it is after the
|
||||
* {@link SecurityConfigurer} in the first step.</li>
|
||||
* <li>We then can default an {@link AuthenticationProvider} if necessary. Note we can
|
||||
|
|
@ -168,14 +168,11 @@ public class AuthenticationManagerConfiguration {
|
|||
if (auth.isConfigured()) {
|
||||
return;
|
||||
}
|
||||
User user = this.securityProperties.getUser();
|
||||
if (user.isDefaultPassword()) {
|
||||
logger.info(String.format("%n%nUsing default security password: %s%n",
|
||||
user.getPassword()));
|
||||
}
|
||||
Set<String> roles = new LinkedHashSet<>(user.getRole());
|
||||
withUser(user.getName()).password(user.getPassword())
|
||||
.roles(roles.toArray(new String[roles.size()]));
|
||||
String password = UUID.randomUUID().toString();
|
||||
logger.info(String.format("%n%nUsing default security password: %s%n",
|
||||
password));
|
||||
withUser("user").password(password)
|
||||
.roles();
|
||||
setField(auth, "defaultUserDetailsService", getUserDetailsService());
|
||||
super.configure(auth);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2015 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
|
||||
*
|
||||
* http://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.boot.autoconfigure.security;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* {@link GlobalAuthenticationConfigurerAdapter} to trigger early initialization of
|
||||
* {@code @EnableAutoConfiguration} beans. This configuration is imported from
|
||||
* {@link AuthenticationConfiguration} to ensure that users are able to configure the
|
||||
* {@link AuthenticationManagerBuilder} from their {@code @EnableAutoConfiguration} or
|
||||
* {@code @SpringBootApplication} configuration class:
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Autowired
|
||||
* public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 1.1.11
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(GlobalAuthenticationConfigurerAdapter.class)
|
||||
public class BootGlobalAuthenticationConfiguration {
|
||||
|
||||
@Bean
|
||||
public static BootGlobalAuthenticationConfigurationAdapter bootGlobalAuthenticationConfigurationAdapter(
|
||||
ApplicationContext context) {
|
||||
return new BootGlobalAuthenticationConfigurationAdapter(context);
|
||||
}
|
||||
|
||||
private static class BootGlobalAuthenticationConfigurationAdapter
|
||||
extends GlobalAuthenticationConfigurerAdapter {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(BootGlobalAuthenticationConfiguration.class);
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
BootGlobalAuthenticationConfigurationAdapter(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(AuthenticationManagerBuilder auth) {
|
||||
Map<String, Object> beansWithAnnotation = this.context
|
||||
.getBeansWithAnnotation(EnableAutoConfiguration.class);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Eagerly initializing " + beansWithAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,10 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.endpoint.DefaultEndpointPathResolver;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
@ -49,10 +53,23 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
|||
GlobalAuthenticationConfigurerAdapter.class })
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
@Import({ SpringBootWebSecurityConfiguration.class,
|
||||
WebSecurityEnablerConfiguration.class,
|
||||
AuthenticationManagerConfiguration.class,
|
||||
BootGlobalAuthenticationConfiguration.class, SecurityDataConfiguration.class })
|
||||
SecurityDataConfiguration.class })
|
||||
public class SecurityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EndpointPathResolver endpointPathResolver() {
|
||||
return new DefaultEndpointPathResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringBootSecurity springBootSecurity(EndpointPathResolver endpointPathResolver,
|
||||
ObjectProvider<ErrorController> errorController) {
|
||||
return new SpringBootSecurity(endpointPathResolver, errorController.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
|
||||
public DefaultAuthenticationEventPublisher authenticationEventPublisher(
|
||||
|
|
|
|||
|
|
@ -16,20 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.DispatcherType;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Properties for the security aspects of an application.
|
||||
|
|
@ -70,33 +64,8 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
public static final int DEFAULT_FILTER_ORDER = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER
|
||||
- 100;
|
||||
|
||||
/**
|
||||
* Enable secure channel for all requests.
|
||||
*/
|
||||
private boolean requireSsl;
|
||||
|
||||
/**
|
||||
* Enable Cross Site Request Forgery support.
|
||||
*/
|
||||
// Flip this when session creation is disabled by default
|
||||
private boolean enableCsrf = false;
|
||||
|
||||
private Basic basic = new Basic();
|
||||
|
||||
private final Headers headers = new Headers();
|
||||
|
||||
/**
|
||||
* Session creation policy (always, never, if_required, stateless).
|
||||
*/
|
||||
private SessionCreationPolicy sessions = SessionCreationPolicy.STATELESS;
|
||||
|
||||
/**
|
||||
* Comma-separated list of paths to exclude from the default secured paths.
|
||||
*/
|
||||
private List<String> ignored = new ArrayList<>();
|
||||
|
||||
private final User user = new User();
|
||||
|
||||
/**
|
||||
* Security filter chain order.
|
||||
*/
|
||||
|
|
@ -108,22 +77,6 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
private Set<DispatcherType> filterDispatcherTypes = new HashSet<>(Arrays.asList(
|
||||
DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
|
||||
|
||||
public Headers getHeaders() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public SessionCreationPolicy getSessions() {
|
||||
return this.sessions;
|
||||
}
|
||||
|
||||
public void setSessions(SessionCreationPolicy sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
public Basic getBasic() {
|
||||
return this.basic;
|
||||
}
|
||||
|
|
@ -132,30 +85,6 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
this.basic = basic;
|
||||
}
|
||||
|
||||
public boolean isRequireSsl() {
|
||||
return this.requireSsl;
|
||||
}
|
||||
|
||||
public void setRequireSsl(boolean requireSsl) {
|
||||
this.requireSsl = requireSsl;
|
||||
}
|
||||
|
||||
public boolean isEnableCsrf() {
|
||||
return this.enableCsrf;
|
||||
}
|
||||
|
||||
public void setEnableCsrf(boolean enableCsrf) {
|
||||
this.enableCsrf = enableCsrf;
|
||||
}
|
||||
|
||||
public void setIgnored(List<String> ignored) {
|
||||
this.ignored = new ArrayList<>(ignored);
|
||||
}
|
||||
|
||||
public List<String> getIgnored() {
|
||||
return this.ignored;
|
||||
}
|
||||
|
||||
public int getFilterOrder() {
|
||||
return this.filterOrder;
|
||||
}
|
||||
|
|
@ -172,122 +101,6 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
this.filterDispatcherTypes = filterDispatcherTypes;
|
||||
}
|
||||
|
||||
public static class Headers {
|
||||
|
||||
public enum HSTS {
|
||||
|
||||
NONE, DOMAIN, ALL
|
||||
|
||||
}
|
||||
|
||||
public enum ContentSecurityPolicyMode {
|
||||
|
||||
/**
|
||||
* Use the 'Content-Security-Policy' header.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Use the 'Content-Security-Policy-Report-Only' header.
|
||||
*/
|
||||
REPORT_ONLY
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable cross site scripting (XSS) protection.
|
||||
*/
|
||||
private boolean xss = true;
|
||||
|
||||
/**
|
||||
* Enable cache control HTTP headers.
|
||||
*/
|
||||
private boolean cache = true;
|
||||
|
||||
/**
|
||||
* Enable "X-Frame-Options" header.
|
||||
*/
|
||||
private boolean frame = true;
|
||||
|
||||
/**
|
||||
* Enable "X-Content-Type-Options" header.
|
||||
*/
|
||||
private boolean contentType = true;
|
||||
|
||||
/**
|
||||
* Value for content security policy header.
|
||||
*/
|
||||
private String contentSecurityPolicy;
|
||||
|
||||
/**
|
||||
* Content security policy mode.
|
||||
*/
|
||||
private ContentSecurityPolicyMode contentSecurityPolicyMode = ContentSecurityPolicyMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* HTTP Strict Transport Security (HSTS) mode (none, domain, all).
|
||||
*/
|
||||
private HSTS hsts = HSTS.ALL;
|
||||
|
||||
public boolean isXss() {
|
||||
return this.xss;
|
||||
}
|
||||
|
||||
public void setXss(boolean xss) {
|
||||
this.xss = xss;
|
||||
}
|
||||
|
||||
public boolean isCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public void setCache(boolean cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public boolean isFrame() {
|
||||
return this.frame;
|
||||
}
|
||||
|
||||
public void setFrame(boolean frame) {
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
public boolean isContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
public void setContentType(boolean contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public String getContentSecurityPolicy() {
|
||||
return this.contentSecurityPolicy;
|
||||
}
|
||||
|
||||
public void setContentSecurityPolicy(String contentSecurityPolicy) {
|
||||
this.contentSecurityPolicy = contentSecurityPolicy;
|
||||
}
|
||||
|
||||
public ContentSecurityPolicyMode getContentSecurityPolicyMode() {
|
||||
return this.contentSecurityPolicyMode;
|
||||
}
|
||||
|
||||
public void setContentSecurityPolicyMode(
|
||||
ContentSecurityPolicyMode contentSecurityPolicyMode) {
|
||||
this.contentSecurityPolicyMode = contentSecurityPolicyMode;
|
||||
}
|
||||
|
||||
public HSTS getHsts() {
|
||||
return this.hsts;
|
||||
}
|
||||
|
||||
public void setHsts(HSTS hsts) {
|
||||
this.hsts = hsts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Basic {
|
||||
|
||||
/**
|
||||
|
|
@ -295,16 +108,6 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* HTTP basic realm name.
|
||||
*/
|
||||
private String realm = "Spring";
|
||||
|
||||
/**
|
||||
* Comma-separated list of paths to secure.
|
||||
*/
|
||||
private String[] path = new String[] { "/**" };
|
||||
|
||||
/**
|
||||
* Security authorize mode to apply.
|
||||
*/
|
||||
|
|
@ -318,84 +121,6 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return this.realm;
|
||||
}
|
||||
|
||||
public void setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public String[] getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String... paths) {
|
||||
this.path = paths;
|
||||
}
|
||||
|
||||
public SecurityAuthorizeMode getAuthorizeMode() {
|
||||
return this.authorizeMode;
|
||||
}
|
||||
|
||||
public void setAuthorizeMode(SecurityAuthorizeMode authorizeMode) {
|
||||
this.authorizeMode = authorizeMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class User {
|
||||
|
||||
/**
|
||||
* Default user name.
|
||||
*/
|
||||
private String name = "user";
|
||||
|
||||
/**
|
||||
* Password for the default user name.
|
||||
*/
|
||||
private String password = UUID.randomUUID().toString();
|
||||
|
||||
/**
|
||||
* Granted roles for the default user name.
|
||||
*/
|
||||
private List<String> role = new ArrayList<>(Collections.singletonList("USER"));
|
||||
|
||||
private boolean defaultPassword = true;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
if (password.startsWith("${") && password.endsWith("}")
|
||||
|| !StringUtils.hasLength(password)) {
|
||||
return;
|
||||
}
|
||||
this.defaultPassword = false;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public List<String> getRole() {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
public void setRole(List<String> role) {
|
||||
this.role = new ArrayList<>(role);
|
||||
}
|
||||
|
||||
public boolean isDefaultPassword() {
|
||||
return this.defaultPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.autoconfigure.security;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
|
||||
import org.springframework.boot.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Provides request matchers that can be used to
|
||||
* configure security for static resources and the error controller path in a custom
|
||||
* {@link WebSecurityConfigurerAdapter}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public final class SpringBootSecurity {
|
||||
|
||||
/**
|
||||
* Used as a wildcard matcher for all endpoints.
|
||||
*/
|
||||
public final static String ALL_ENDPOINTS = "**";
|
||||
|
||||
private static String[] STATIC_RESOURCES = new String[]{"/css/**", "/js/**",
|
||||
"/images/**", "/webjars/**", "/**/favicon.ico"};
|
||||
|
||||
private final EndpointPathResolver endpointPathResolver;
|
||||
|
||||
private final ErrorController errorController;
|
||||
|
||||
SpringBootSecurity(EndpointPathResolver endpointPathResolver, ErrorController errorController) {
|
||||
this.endpointPathResolver = endpointPathResolver;
|
||||
this.errorController = errorController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RequestMatcher} that matches on all endpoint paths with given ids.
|
||||
* @param ids the endpoint ids
|
||||
* @return the request matcher
|
||||
*/
|
||||
public RequestMatcher endpointIds(String... ids) {
|
||||
Assert.notEmpty(ids, "At least one endpoint id must be specified.");
|
||||
List<String> pathList = Arrays.asList(ids);
|
||||
if (pathList.contains(ALL_ENDPOINTS)) {
|
||||
return new AntPathRequestMatcher(this.endpointPathResolver.resolvePath(ALL_ENDPOINTS), null);
|
||||
}
|
||||
return getEndpointsRequestMatcher(pathList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RequestMatcher} that matches on all endpoint paths for the given
|
||||
* classes with the {@link Endpoint} annotation.
|
||||
* @param endpoints the endpoint classes
|
||||
* @return the request matcher
|
||||
*/
|
||||
public RequestMatcher endpoints(Class<?>... endpoints) {
|
||||
Assert.notEmpty(endpoints, "At least one endpoint must be specified.");
|
||||
List<String> paths = Arrays.stream(endpoints).map(e -> {
|
||||
if (e.isAnnotationPresent(Endpoint.class)) {
|
||||
return e.getAnnotation(Endpoint.class).id();
|
||||
}
|
||||
throw new IllegalArgumentException("Only classes annotated with @Endpoint are supported.");
|
||||
}).collect(Collectors.toList());
|
||||
return getEndpointsRequestMatcher(paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RequestMatcher} that matches on all static resources.
|
||||
* @return the request matcher
|
||||
*/
|
||||
public RequestMatcher staticResources() {
|
||||
return getRequestMatcher(STATIC_RESOURCES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link RequestMatcher} that matches on the {@link ErrorController} path,
|
||||
* if present.
|
||||
* @return the request matcher
|
||||
*/
|
||||
public RequestMatcher error() {
|
||||
if (this.errorController == null) {
|
||||
throw new IllegalStateException("Path for error controller could not be determined.");
|
||||
}
|
||||
String path = normalizePath(this.errorController.getErrorPath());
|
||||
return new AntPathRequestMatcher(path + "/**", null);
|
||||
}
|
||||
|
||||
private RequestMatcher getEndpointsRequestMatcher(List<String> ids) {
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
String path = this.endpointPathResolver.resolvePath(id);
|
||||
matchers.add(new AntPathRequestMatcher(path + "/**", null));
|
||||
}
|
||||
return new OrRequestMatcher(matchers);
|
||||
}
|
||||
|
||||
private static RequestMatcher getRequestMatcher(String... paths) {
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
matchers.add(new AntPathRequestMatcher(path, null));
|
||||
}
|
||||
return new OrRequestMatcher(matchers);
|
||||
}
|
||||
|
||||
private String normalizePath(String errorPath) {
|
||||
String result = StringUtils.cleanPath(errorPath);
|
||||
if (!result.startsWith("/")) {
|
||||
result = "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -16,284 +16,41 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers.ContentSecurityPolicyMode;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration for security of a web application or service. By default everything is
|
||||
* secured with HTTP Basic authentication except the
|
||||
* {@link SecurityProperties#getIgnored() explicitly ignored} paths (defaults to
|
||||
* <code>/css/**, /js/**, /images/**, /**/favicon.ico</code>
|
||||
* ). Many aspects of the behavior can be controller with {@link SecurityProperties} via
|
||||
* externalized application properties (or via an bean definition of that type to set the
|
||||
* defaults). The user details for authentication are just placeholders
|
||||
* {@code (username=user, password=password)} but can easily be customized by providing a
|
||||
* an {@link AuthenticationManager}. Also provides audit logging of authentication events.
|
||||
* <p>
|
||||
* Some common simple customizations:
|
||||
* <ul>
|
||||
* <li>Switch off security completely and permanently: remove Spring Security from the
|
||||
* classpath or {@link EnableAutoConfiguration#exclude() exclude}
|
||||
* {@link SecurityAutoConfiguration}.</li>
|
||||
* <li>Switch off security temporarily (e.g. for a dev environment): set
|
||||
* {@code security.basic.enabled=false}</li>
|
||||
* <li>Customize the user details: autowire an {@link AuthenticationManagerBuilder} into a
|
||||
* method in one of your configuration classes or equivalently add a bean of type
|
||||
* AuthenticationManager</li>
|
||||
* <li>Add form login for user facing resources: add a
|
||||
* {@link WebSecurityConfigurerAdapter} and use {@link HttpSecurity#formLogin()}</li>
|
||||
* </ul>
|
||||
* The default configuration for web security. It relies on Spring Security's
|
||||
* content-negotiation strategy to determine what sort of authentication to use.
|
||||
* If the user specifies their own {@link WebSecurityConfigurerAdapter}, this will back-off
|
||||
* completely and the users should specify all the bits that they want to configure as part
|
||||
* of the custom security configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ServerProperties.class)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, AuthenticationEntryPoint.class })
|
||||
@ConditionalOnMissingBean(WebSecurityConfiguration.class)
|
||||
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnClass(EnableWebSecurity.class)
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@EnableWebSecurity
|
||||
public class SpringBootWebSecurityConfiguration {
|
||||
|
||||
private static List<String> DEFAULT_IGNORED = Arrays.asList("/css/**", "/js/**",
|
||||
"/images/**", "/webjars/**", "/**/favicon.ico");
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ IgnoredPathsWebSecurityConfigurerAdapter.class })
|
||||
public IgnoredPathsWebSecurityConfigurerAdapter ignoredPathsWebSecurityConfigurerAdapter(
|
||||
List<IgnoredRequestCustomizer> customizers) {
|
||||
return new IgnoredPathsWebSecurityConfigurerAdapter(customizers);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IgnoredRequestCustomizer defaultIgnoredRequestsCustomizer(
|
||||
ServerProperties server, SecurityProperties security,
|
||||
ObjectProvider<ErrorController> errorController) {
|
||||
return new DefaultIgnoredRequestCustomizer(server, security,
|
||||
errorController.getIfAvailable());
|
||||
}
|
||||
|
||||
public static void configureHeaders(HeadersConfigurer<?> configurer,
|
||||
SecurityProperties.Headers headers) throws Exception {
|
||||
if (headers.getHsts() != Headers.HSTS.NONE) {
|
||||
boolean includeSubDomains = headers.getHsts() == Headers.HSTS.ALL;
|
||||
HstsHeaderWriter writer = new HstsHeaderWriter(includeSubDomains);
|
||||
writer.setRequestMatcher(AnyRequestMatcher.INSTANCE);
|
||||
configurer.addHeaderWriter(writer);
|
||||
}
|
||||
if (!headers.isContentType()) {
|
||||
configurer.contentTypeOptions().disable();
|
||||
}
|
||||
if (StringUtils.hasText(headers.getContentSecurityPolicy())) {
|
||||
String policyDirectives = headers.getContentSecurityPolicy();
|
||||
ContentSecurityPolicyMode mode = headers.getContentSecurityPolicyMode();
|
||||
if (mode == ContentSecurityPolicyMode.DEFAULT) {
|
||||
configurer.contentSecurityPolicy(policyDirectives);
|
||||
}
|
||||
else {
|
||||
configurer.contentSecurityPolicy(policyDirectives).reportOnly();
|
||||
}
|
||||
}
|
||||
if (!headers.isXss()) {
|
||||
configurer.xssProtection().disable();
|
||||
}
|
||||
if (!headers.isCache()) {
|
||||
configurer.cacheControl().disable();
|
||||
}
|
||||
if (!headers.isFrame()) {
|
||||
configurer.frameOptions().disable();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the ignored paths in early
|
||||
@Order(SecurityProperties.IGNORED_ORDER)
|
||||
private static class IgnoredPathsWebSecurityConfigurerAdapter
|
||||
implements WebSecurityConfigurer<WebSecurity> {
|
||||
|
||||
private final List<IgnoredRequestCustomizer> customizers;
|
||||
|
||||
IgnoredPathsWebSecurityConfigurerAdapter(
|
||||
List<IgnoredRequestCustomizer> customizers) {
|
||||
this.customizers = customizers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(WebSecurity builder) throws Exception {
|
||||
for (IgnoredRequestCustomizer customizer : this.customizers) {
|
||||
customizer.customize(builder.ignoring());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DefaultIgnoredRequestCustomizer implements IgnoredRequestCustomizer {
|
||||
|
||||
private final ServerProperties server;
|
||||
|
||||
private final SecurityProperties security;
|
||||
|
||||
private final ErrorController errorController;
|
||||
|
||||
DefaultIgnoredRequestCustomizer(ServerProperties server,
|
||||
SecurityProperties security, ErrorController errorController) {
|
||||
this.server = server;
|
||||
this.security = security;
|
||||
this.errorController = errorController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(IgnoredRequestConfigurer configurer) {
|
||||
List<String> ignored = getIgnored(this.security);
|
||||
if (this.errorController != null) {
|
||||
ignored.add(normalizePath(this.errorController.getErrorPath()));
|
||||
}
|
||||
String[] paths = this.server.getServlet().getPathsArray(ignored);
|
||||
List<RequestMatcher> matchers = new ArrayList<>();
|
||||
if (!ObjectUtils.isEmpty(paths)) {
|
||||
for (String pattern : paths) {
|
||||
matchers.add(new AntPathRequestMatcher(pattern, null));
|
||||
}
|
||||
}
|
||||
if (!matchers.isEmpty()) {
|
||||
configurer.requestMatchers(new OrRequestMatcher(matchers));
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getIgnored(SecurityProperties security) {
|
||||
List<String> ignored = new ArrayList<>(security.getIgnored());
|
||||
if (ignored.isEmpty()) {
|
||||
ignored.addAll(DEFAULT_IGNORED);
|
||||
}
|
||||
else if (ignored.contains("none")) {
|
||||
ignored.remove("none");
|
||||
}
|
||||
return ignored;
|
||||
}
|
||||
|
||||
private String normalizePath(String errorPath) {
|
||||
String result = StringUtils.cleanPath(errorPath);
|
||||
if (!result.startsWith("/")) {
|
||||
result = "/" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", havingValue = "false")
|
||||
@Order(SecurityProperties.BASIC_AUTH_ORDER)
|
||||
protected static class ApplicationNoWebSecurityConfigurerAdapter
|
||||
extends WebSecurityConfigurerAdapter {
|
||||
static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher((request) -> false);
|
||||
super.configure(http);
|
||||
http.csrf().disable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", matchIfMissing = true)
|
||||
@Order(SecurityProperties.BASIC_AUTH_ORDER)
|
||||
protected static class ApplicationWebSecurityConfigurerAdapter
|
||||
extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private SecurityProperties security;
|
||||
|
||||
protected ApplicationWebSecurityConfigurerAdapter(SecurityProperties security) {
|
||||
this.security = security;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
if (this.security.isRequireSsl()) {
|
||||
http.requiresChannel().anyRequest().requiresSecure();
|
||||
}
|
||||
if (!this.security.isEnableCsrf()) {
|
||||
http.csrf().disable();
|
||||
}
|
||||
// No cookies for application endpoints by default
|
||||
http.sessionManagement().sessionCreationPolicy(this.security.getSessions());
|
||||
SpringBootWebSecurityConfiguration.configureHeaders(http.headers(),
|
||||
this.security.getHeaders());
|
||||
String[] paths = getSecureApplicationPaths();
|
||||
if (paths.length > 0) {
|
||||
AuthenticationEntryPoint entryPoint = entryPoint();
|
||||
http.exceptionHandling().authenticationEntryPoint(entryPoint);
|
||||
http.httpBasic().authenticationEntryPoint(entryPoint);
|
||||
http.requestMatchers().antMatchers(paths);
|
||||
String[] roles = this.security.getUser().getRole().toArray(new String[0]);
|
||||
SecurityAuthorizeMode mode = this.security.getBasic().getAuthorizeMode();
|
||||
if (mode == null || mode == SecurityAuthorizeMode.ROLE) {
|
||||
http.authorizeRequests().anyRequest().hasAnyRole(roles);
|
||||
}
|
||||
else if (mode == SecurityAuthorizeMode.AUTHENTICATED) {
|
||||
http.authorizeRequests().anyRequest().authenticated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getSecureApplicationPaths() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String path : this.security.getBasic().getPath()) {
|
||||
path = (path == null ? "" : path.trim());
|
||||
if (path.equals("/**")) {
|
||||
return new String[] { path };
|
||||
}
|
||||
if (!path.equals("")) {
|
||||
list.add(path);
|
||||
}
|
||||
}
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
private AuthenticationEntryPoint entryPoint() {
|
||||
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
|
||||
entryPoint.setRealmName(this.security.getBasic().getRealm());
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,33 +16,27 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* If the user explicitly disables the basic security features and forgets to
|
||||
* {@code @EnableWebSecurity}, and yet still wants a bean of type
|
||||
* WebSecurityConfigurerAdapter, he is trying to use a custom security setup. The app
|
||||
* would fail in a confusing way without this shim configuration, which just helpfully
|
||||
* defines an empty {@code @EnableWebSecurity}.
|
||||
* If there is a bean of type WebSecurityConfigurerAdapter,
|
||||
* this adds the {@code @EnableWebSecurity} annotation if it is not already specified.
|
||||
* This will make sure that the annotation is present with default security autoconfiguration
|
||||
* and also if the user adds custom security and forgets to add the annotation.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@ConditionalOnProperty(prefix = "security.basic", name = "enabled", havingValue = "false")
|
||||
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnClass(EnableWebSecurity.class)
|
||||
@ConditionalOnMissingBean(WebSecurityConfiguration.class)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@AutoConfigureAfter(SecurityAutoConfiguration.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@EnableWebSecurity
|
||||
public class FallbackWebSecurityAutoConfiguration {
|
||||
|
||||
public class WebSecurityEnablerConfiguration {
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,6 @@ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
|
|||
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfigurationInteg
|
|||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
|
@ -60,26 +61,18 @@ public class H2ConsoleAutoConfigurationIntegrationTests {
|
|||
public void noPrincipal() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(springSecurity()).build();
|
||||
mockMvc.perform(get("/h2-console/")).andExpect(status().isUnauthorized());
|
||||
mockMvc.perform(get("/h2-console/").accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userPrincipal() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(springSecurity()).build();
|
||||
mockMvc.perform(get("/h2-console/").with(user("test").roles("USER")))
|
||||
mockMvc.perform(get("/h2-console/").accept(MediaType.APPLICATION_JSON).with(user("test").roles("USER")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string("X-Frame-Options", "SAMEORIGIN"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void someOtherPrincipal() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(springSecurity()).build();
|
||||
mockMvc.perform(get("/h2-console/").with(user("test").roles("FOO")))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ SecurityAutoConfiguration.class, H2ConsoleAutoConfiguration.class })
|
||||
@Controller
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.util.EnumSet;
|
|||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
|
|
@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon
|
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
|
|
@ -50,7 +52,6 @@ import org.springframework.security.config.annotation.authentication.configurers
|
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
|
||||
|
|
@ -72,6 +73,9 @@ public class SecurityAutoConfigurationTests {
|
|||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
|
|
@ -87,9 +91,8 @@ public class SecurityAutoConfigurationTests {
|
|||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
|
||||
// 1 for static resources and one for the rest
|
||||
assertThat(this.context.getBean(FilterChainProxy.class).getFilterChains())
|
||||
.hasSize(2);
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -157,7 +160,7 @@ public class SecurityAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDisableBasicAuthOnApplicationPaths() throws Exception {
|
||||
public void testDisableDefaultSecurity() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
|
|
@ -166,7 +169,7 @@ public class SecurityAutoConfigurationTests {
|
|||
this.context.refresh();
|
||||
// Ignores and the "matches-none" filter only
|
||||
assertThat(this.context.getBeanNamesForType(FilterChainProxy.class).length)
|
||||
.isEqualTo(1);
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -295,33 +298,24 @@ public class SecurityAutoConfigurationTests {
|
|||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
SecurityProperties security = this.context.getBean(SecurityProperties.class);
|
||||
String password = this.outputCapture.toString().split("Using default security password: ")[1].split("\n")[0];
|
||||
AuthenticationManager manager = this.context.getBean(AuthenticationManager.class);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
security.getUser().getName(), security.getUser().getPassword());
|
||||
"user", password);
|
||||
assertThat(manager.authenticate(token)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomAuthenticationDoesNotAuthenticateWithBootSecurityUser()
|
||||
public void testCustomAuthenticationDoesNotCreateDefaultUser()
|
||||
throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(AuthenticationManagerCustomizer.class,
|
||||
SecurityAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
SecurityProperties security = this.context.getBean(SecurityProperties.class);
|
||||
AuthenticationManager manager = this.context.getBean(AuthenticationManager.class);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
security.getUser().getName(), security.getUser().getPassword());
|
||||
try {
|
||||
manager.authenticate(token);
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (AuthenticationException success) {
|
||||
// Expected
|
||||
}
|
||||
token = new UsernamePasswordAuthenticationToken("foo", "bar");
|
||||
assertThat(this.outputCapture.toString()).doesNotContain("Using default security password: ");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("foo", "bar");
|
||||
assertThat(manager.authenticate(token)).isNotNull();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -30,9 +31,9 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfigurationTests.WebSecurity;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
|
|
@ -54,17 +55,19 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
*/
|
||||
public class SecurityFilterAutoConfigurationEarlyInitializationTests {
|
||||
|
||||
// gh-4154
|
||||
@Rule
|
||||
public OutputCapture outputCapture = new OutputCapture();
|
||||
|
||||
@Test
|
||||
public void testSecurityFilterDoesNotCauseEarlyInitialization() throws Exception {
|
||||
try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {
|
||||
TestPropertyValues.of("server.port:0", "security.user.password:password")
|
||||
TestPropertyValues.of("server.port:0")
|
||||
.applyTo(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
int port = context.getWebServer().getPort();
|
||||
new TestRestTemplate("user", "password")
|
||||
String password = this.outputCapture.toString().split("Using default security password: ")[1].split("\n")[0];
|
||||
new TestRestTemplate("user", password)
|
||||
.getForEntity("http://localhost:" + port, Object.class);
|
||||
// If early initialization occurred a ConverterNotFoundException is thrown
|
||||
|
||||
|
|
@ -76,7 +79,7 @@ public class SecurityFilterAutoConfigurationEarlyInitializationTests {
|
|||
ConverterBean.class })
|
||||
@ImportAutoConfiguration({ WebMvcAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebSecurity.class,
|
||||
DispatcherServletAutoConfiguration.class,
|
||||
SecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
static class Config {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -39,63 +37,9 @@ public class SecurityPropertiesTests {
|
|||
private SecurityProperties security = new SecurityProperties();
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredSingleValued() {
|
||||
bind("security.ignored", "/css/**");
|
||||
assertThat(this.security.getIgnored()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredEmpty() {
|
||||
bind("security.ignored", "");
|
||||
assertThat(this.security.getIgnored()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredDisable() {
|
||||
bind("security.ignored", "none");
|
||||
assertThat(this.security.getIgnored()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredMultiValued() {
|
||||
bind("security.ignored", "/css/**,/images/**");
|
||||
assertThat(this.security.getIgnored()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredMultiValuedList() {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
map.put("security.ignored[0]", "/css/**");
|
||||
map.put("security.ignored[1]", "/foo/**");
|
||||
MapConfigurationPropertySource source = new MapConfigurationPropertySource(map);
|
||||
bind(source);
|
||||
assertThat(this.security.getIgnored()).hasSize(2);
|
||||
assertThat(this.security.getIgnored().contains("/foo/**")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutogeneratedIfUnresolvedPlaceholder() {
|
||||
bind("security.user.password", "${ADMIN_PASSWORD}");
|
||||
assertThat(this.security.getUser().isDefaultPassword()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutogeneratedIfEmpty() {
|
||||
bind("security.user.password", "");
|
||||
assertThat(this.security.getUser().isDefaultPassword()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoles() {
|
||||
bind("security.user.role", "USER,ADMIN");
|
||||
assertThat(this.security.getUser().getRole().toString())
|
||||
.isEqualTo("[USER, ADMIN]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRole() {
|
||||
bind("security.user.role", "ADMIN");
|
||||
assertThat(this.security.getUser().getRole().toString()).isEqualTo("[ADMIN]");
|
||||
public void testBinding() {
|
||||
bind("security.basic.enabled", "false");
|
||||
assertThat(this.security.getBasic().isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
private void bind(String name, String value) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.autoconfigure.security;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
|
||||
import org.springframework.boot.endpoint.Endpoint;
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringBootSecurity}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class SpringBootSecurityTests {
|
||||
|
||||
private SpringBootSecurity bootSecurity;
|
||||
|
||||
private EndpointPathResolver endpointPathResolver = new TestEndpointPathResolver();
|
||||
|
||||
private ErrorController errorController = new TestErrorController();
|
||||
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
private static String[] STATIC_RESOURCES = new String[]{"/css/**", "/js/**",
|
||||
"/images/**", "/webjars/**", "/**/favicon.ico"};
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver, this.errorController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointIdsShouldThrowIfNoEndpointPaths() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("At least one endpoint id must be specified.");
|
||||
this.bootSecurity.endpointIds();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointIdsShouldReturnRequestMatcherWithEndpointPaths() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.endpointIds("id-1", "id-2");
|
||||
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
|
||||
this.request.setServletPath("/test/id-1");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/id-2");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/other-id");
|
||||
assertThat(requestMatcher.matches(this.request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointIdsShouldReturnRequestMatcherWithAllEndpointPaths() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS);
|
||||
this.request.setServletPath("/test/id-1");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/id-2");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/other-id");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointsShouldReturnRequestMatcherWithEndpointPaths() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.endpoints(TestEndpoint1.class);
|
||||
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
|
||||
this.request.setServletPath("/test/id-1");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/id-2");
|
||||
assertThat(requestMatcher.matches(this.request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointsShouldThrowIfNoEndpointPaths() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("At least one endpoint must be specified.");
|
||||
this.bootSecurity.endpoints();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointsShouldThrowExceptionWhenClassNotEndpoint() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Only classes annotated with @Endpoint are supported.");
|
||||
this.bootSecurity.endpoints(FakeEndpoint.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticResourcesShouldReturnRequestMatcherWithStaticResources() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.staticResources();
|
||||
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
|
||||
for (String resource : STATIC_RESOURCES) {
|
||||
this.request.setServletPath(resource);
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorShouldReturnRequestMatcherWithErrorControllerPath() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.error();
|
||||
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
|
||||
this.request.setServletPath("/test/error");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorShouldThrowExceptionWhenNoErrorController() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Path for error controller could not be determined.");
|
||||
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver, null);
|
||||
this.bootSecurity.error();
|
||||
}
|
||||
|
||||
static class TestEndpointPathResolver implements EndpointPathResolver {
|
||||
|
||||
@Override
|
||||
public String resolvePath(String endpointId) {
|
||||
return "/test/" + endpointId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestErrorController implements ErrorController {
|
||||
|
||||
@Override
|
||||
public String getErrorPath() {
|
||||
return "/test/error";
|
||||
}
|
||||
}
|
||||
|
||||
@Endpoint(id = "id-1")
|
||||
static class TestEndpoint1 {
|
||||
|
||||
}
|
||||
|
||||
@Endpoint(id = "id-2")
|
||||
static class TestEndpoint2 {
|
||||
|
||||
}
|
||||
|
||||
static class FakeEndpoint {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,343 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.autoconfigure.security;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringBootWebSecurityConfiguration}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Rob Winch
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SpringBootWebSecurityConfigurationTests {
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationOverrideGlobalAuthentication() throws Exception {
|
||||
this.context = SpringApplication.run(TestWebConfiguration.class,
|
||||
"--server.port=0");
|
||||
assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
|
||||
assertThat(this.context.getBean(AuthenticationManager.class)
|
||||
.authenticate(new UsernamePasswordAuthenticationToken("dave", "secret")))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationFilterChainUnauthenticated() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters(
|
||||
this.context.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(MockMvcResultMatchers.header().string("www-authenticate",
|
||||
Matchers.containsString("realm=\"Spring\"")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationFilterChainUnauthenticatedWithAuthorizeModeNone()
|
||||
throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0", "--security.basic.authorize-mode=none");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters(
|
||||
this.context.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationFilterChainUnauthenticatedWithAuthorizeModeAuthenticated()
|
||||
throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0", "--security.basic.authorize-mode=authenticated");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters(
|
||||
this.context.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(MockMvcResultMatchers.header().string("www-authenticate",
|
||||
Matchers.containsString("realm=\"Spring\"")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationFilterChainBadCredentials() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters(
|
||||
this.context.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.get("/").header("authorization", "Basic xxx"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(MockMvcResultMatchers.header().string("www-authenticate",
|
||||
Matchers.containsString("realm=\"Spring\"")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebConfigurationInjectGlobalAuthentication() throws Exception {
|
||||
this.context = SpringApplication.run(TestInjectWebConfiguration.class,
|
||||
"--server.port=0");
|
||||
assertThat(this.context.getBean(AuthenticationManagerBuilder.class)).isNotNull();
|
||||
assertThat(this.context.getBean(AuthenticationManager.class)
|
||||
.authenticate(new UsernamePasswordAuthenticationToken("dave", "secret")))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
// gh-3447
|
||||
@Test
|
||||
public void testHiddenHttpMethodFilterOrderedFirst() throws Exception {
|
||||
this.context = SpringApplication.run(DenyPostRequestConfig.class,
|
||||
"--server.port=0");
|
||||
int port = Integer
|
||||
.parseInt(this.context.getEnvironment().getProperty("local.server.port"));
|
||||
TestRestTemplate rest = new TestRestTemplate();
|
||||
|
||||
// not overriding causes forbidden
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
|
||||
ResponseEntity<Object> result = rest
|
||||
.postForEntity("http://localhost:" + port + "/", form, Object.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
|
||||
// override method with GET
|
||||
form = new LinkedMultiValueMap<>();
|
||||
form.add("_method", "GET");
|
||||
|
||||
result = rest.postForEntity("http://localhost:" + port + "/", form, Object.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultHeaderConfiguration() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters((FilterChainProxy) this.context
|
||||
.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.header().string("X-Content-Type-Options",
|
||||
is(notNullValue())))
|
||||
.andExpect(MockMvcResultMatchers.header().string("X-XSS-Protection",
|
||||
is(notNullValue())))
|
||||
.andExpect(MockMvcResultMatchers.header().string("Cache-Control",
|
||||
is(notNullValue())))
|
||||
.andExpect(MockMvcResultMatchers.header().string("X-Frame-Options",
|
||||
is(notNullValue())))
|
||||
.andExpect(MockMvcResultMatchers.header()
|
||||
.doesNotExist("Content-Security-Policy"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securityHeadersCanBeDisabled() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--server.port=0", "--security.headers.content-type=false",
|
||||
"--security.headers.xss=false", "--security.headers.cache=false",
|
||||
"--security.headers.frame=false");
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters(
|
||||
this.context.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.status().isUnauthorized())
|
||||
.andExpect(MockMvcResultMatchers.header()
|
||||
.doesNotExist("X-Content-Type-Options"))
|
||||
.andExpect(
|
||||
MockMvcResultMatchers.header().doesNotExist("X-XSS-Protection"))
|
||||
.andExpect(MockMvcResultMatchers.header().doesNotExist("Cache-Control"))
|
||||
.andExpect(
|
||||
MockMvcResultMatchers.header().doesNotExist("X-Frame-Options"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentSecurityPolicyConfiguration() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--security.headers.content-security-policy=default-src 'self';",
|
||||
"--server.port=0");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters((FilterChainProxy) this.context
|
||||
.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.header()
|
||||
.string("Content-Security-Policy", is("default-src 'self';")))
|
||||
.andExpect(MockMvcResultMatchers.header()
|
||||
.doesNotExist("Content-Security-Policy-Report-Only"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentSecurityPolicyReportOnlyConfiguration() throws Exception {
|
||||
this.context = SpringApplication.run(VanillaWebConfiguration.class,
|
||||
"--security.headers.content-security-policy=default-src 'self';",
|
||||
"--security.headers.content-security-policy-mode=report-only",
|
||||
"--server.port=0");
|
||||
MockMvc mockMvc = MockMvcBuilders
|
||||
.webAppContextSetup((WebApplicationContext) this.context)
|
||||
.addFilters((FilterChainProxy) this.context
|
||||
.getBean("springSecurityFilterChain", Filter.class))
|
||||
.build();
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/"))
|
||||
.andExpect(MockMvcResultMatchers.header().string(
|
||||
"Content-Security-Policy-Report-Only", is("default-src 'self';")))
|
||||
.andExpect(MockMvcResultMatchers.header()
|
||||
.doesNotExist("Content-Security-Policy"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestWebConfiguration.class)
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
protected static class TestInjectWebConfiguration
|
||||
extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final AuthenticationManagerBuilder auth;
|
||||
|
||||
// It's a bad idea to inject an AuthenticationManager into a
|
||||
// WebSecurityConfigurerAdapter because it can cascade early instantiation,
|
||||
// unless you explicitly want the Boot default AuthenticationManager. It's
|
||||
// better to inject the builder, if you want the global AuthenticationManager. It
|
||||
// might even be necessary to wrap the builder in a lazy AuthenticationManager
|
||||
// (that calls getOrBuild() only when the AuthenticationManager is actually
|
||||
// called).
|
||||
protected TestInjectWebConfiguration(AuthenticationManagerBuilder auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(WebSecurity web) throws Exception {
|
||||
this.auth.getOrBuild();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MinimalWebConfiguration
|
||||
@Import(SecurityAutoConfiguration.class)
|
||||
protected static class VanillaWebConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@MinimalWebConfiguration
|
||||
@Import(SecurityAutoConfiguration.class)
|
||||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
|
||||
protected static class TestWebConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("dave").password("secret")
|
||||
.roles("USER");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().denyAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ ServletWebServerFactoryAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@MinimalWebConfiguration
|
||||
@Import(SecurityAutoConfiguration.class)
|
||||
protected static class DenyPostRequestConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().antMatchers(HttpMethod.POST, "/**").denyAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,7 +40,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
|
@ -76,12 +75,6 @@ public class CustomOAuth2SsoConfigurationTests {
|
|||
.addFilters(this.filter).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homePageIsBasicAuth() throws Exception {
|
||||
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", startsWith("Basic")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uiPageIsSecure() throws Exception {
|
||||
this.mvc.perform(get("/ui/")).andExpect(status().isFound())
|
||||
|
|
|
|||
|
|
@ -42,10 +42,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
|
|
@ -78,12 +76,6 @@ public class CustomOAuth2SsoWithAuthenticationEntryPointConfigurationTests {
|
|||
.addFilters(this.filter).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homePageIsBasicAuth() throws Exception {
|
||||
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", startsWith("Basic")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uiPageIsSecure() throws Exception {
|
||||
this.mvc.perform(get("/ui/")).andExpect(status().isUnauthorized());
|
||||
|
|
|
|||
|
|
@ -16,17 +16,21 @@
|
|||
|
||||
package sample;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class HelloWebSecurityApplication {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public class HelloWebSecurityApplicationTests {
|
|||
|
||||
@Test
|
||||
public void requiresAuthentication() throws Exception {
|
||||
this.request.addHeader("Accept", "application/json");
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
assertThat(this.response.getStatus())
|
||||
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
|
@ -64,6 +65,7 @@ public class HelloWebSecurityApplicationTests {
|
|||
|
||||
@Test
|
||||
public void userAuthenticates() throws Exception {
|
||||
this.request.addHeader("Accept", "application/json");
|
||||
this.request.addHeader("Authorization", "Basic " + new String(
|
||||
Base64.getEncoder().encode("user:password".getBytes("UTF-8"))));
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
<module>spring-boot-sample-actuator-log4j2</module>
|
||||
<module>spring-boot-sample-actuator-noweb</module>
|
||||
<module>spring-boot-sample-actuator-ui</module>
|
||||
<module>spring-boot-sample-actuator-custom-security</module>
|
||||
<module>spring-boot-sample-amqp</module>
|
||||
<module>spring-boot-sample-aop</module>
|
||||
<module>spring-boot-sample-atmosphere</module>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-actuator-custom-security</artifactId>
|
||||
<name>Spring Boot Actuator Custom Security Sample</name>
|
||||
<description>Spring Boot Actuator Custom Security Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jolokia</groupId>
|
||||
<artifactId>jolokia-core</artifactId>
|
||||
</dependency>
|
||||
<!-- Runtime -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package sample.actuator.customsecurity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class ExampleController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
model.put("title", "Hello Home");
|
||||
model.put("date", new Date());
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/foo")
|
||||
public String foo() {
|
||||
throw new RuntimeException("Expected exception in controller");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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 sample.actuator.customsecurity;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleActuatorCustomSecurityApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(SampleActuatorCustomSecurityApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package sample.actuator.customsecurity;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private SpringBootSecurity bootSecurity;
|
||||
|
||||
public SecurityConfiguration(SpringBootSecurity bootSecurity) {
|
||||
this.bootSecurity = bootSecurity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
.withUser("user").password("password").authorities("ROLE_USER").and()
|
||||
.withUser("admin").password("admin").authorities("ROLE_ACTUATOR", "ROLE_USER");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.requestMatchers(this.bootSecurity.endpointIds("status", "info")).permitAll()
|
||||
.requestMatchers(this.bootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS)).hasRole("ACTUATOR")
|
||||
.requestMatchers(this.bootSecurity.staticResources()).permitAll()
|
||||
.antMatchers("/foo").permitAll()
|
||||
.antMatchers("/**").hasRole("USER")
|
||||
.and()
|
||||
.cors()
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
endpoints.all.web.enabled=true
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,32 @@
|
|||
<#import "/spring.ftl" as spring />
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<#assign home><@spring.url relativeUrl="/"/></#assign>
|
||||
<#assign bootstrap><@spring.url relativeUrl="/css/bootstrap.min.css"/></#assign>
|
||||
<link rel="stylesheet" href="${bootstrap}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="http://freemarker.org/"> FreeMarker -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a href="${home}"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1>Error Page</h1>
|
||||
<div id="created">${timestamp?datetime}</div>
|
||||
<div>
|
||||
There was an unexpected error (type=${error}, status=${status}).
|
||||
</div>
|
||||
<div>${message}</div>
|
||||
<div>
|
||||
Please contact the operator with the above information.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<#import "/spring.ftl" as spring />
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${title}</title>
|
||||
<#assign home><@spring.url relativeUrl="/"/></#assign>
|
||||
<#assign bootstrap><@spring.url relativeUrl="/css/bootstrap.min.css"/></#assign>
|
||||
<link rel="stylesheet" href="${bootstrap}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<a class="brand" href="http://freemarker.org/"> FreeMarker -
|
||||
Plain </a>
|
||||
<ul class="nav">
|
||||
<li><a href="${home}"> Home </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h1>${title}</h1>
|
||||
<div>${message}</div>
|
||||
<div id="created">${date?datetime}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package sample.actuator;
|
||||
package sample.actuator.customsecurity;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
|
@ -12,10 +12,14 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
|
@ -59,7 +63,7 @@ public class CorsSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void preflightRequestToEndpointShouldReturnOk() throws Exception {
|
||||
RequestEntity<?> healthRequest = RequestEntity
|
||||
.options(new URI("/application/health"))
|
||||
.options(new URI("/application/env"))
|
||||
.header("Origin", "http://localhost:8080")
|
||||
.header("Access-Control-Request-Method", "GET").build();
|
||||
ResponseEntity<?> exchange = this.testRestTemplate.exchange(healthRequest,
|
||||
|
|
@ -70,7 +74,7 @@ public class CorsSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void preflightRequestWhenCorsConfigInvalidShouldReturnForbidden()
|
||||
throws Exception {
|
||||
RequestEntity<?> entity = RequestEntity.options(new URI("/application/health"))
|
||||
RequestEntity<?> entity = RequestEntity.options(new URI("/application/env"))
|
||||
.header("Origin", "http://localhost:9095")
|
||||
.header("Access-Control-Request-Method", "GET").build();
|
||||
ResponseEntity<byte[]> exchange = this.testRestTemplate.exchange(entity,
|
||||
|
|
@ -14,16 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample.actuator;
|
||||
|
||||
import java.util.Map;
|
||||
package sample.actuator.customsecurity;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -39,17 +35,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* Integration tests for separate management and main service ports.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"management.port=0", "management.context-path=/admin",
|
||||
"management.security.enabled=false" })
|
||||
"management.port=0", "management.context-path=/admin"})
|
||||
@DirtiesContext
|
||||
public class InsecureManagementPortAndPathSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 9010;
|
||||
|
||||
|
|
@ -59,43 +52,36 @@ public class InsecureManagementPortAndPathSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword())
|
||||
.getForEntity("http://localhost:" + this.port, Map.class);
|
||||
ResponseEntity<String> entity = new TestRestTemplate("user", "password")
|
||||
.getForEntity("http://localhost:" + this.port, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("message")).isEqualTo("Hello Phil");
|
||||
assertThat(entity.getBody()).contains("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetrics() throws Exception {
|
||||
testHome(); // makes sure some requests have been made
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/metrics", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHealth() throws Exception {
|
||||
public void testSecureActuator() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/health",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsecureActuator() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/status",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissing() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||
ResponseEntity<String> entity = new TestRestTemplate("admin", "admin").getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/missing",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(entity.getBody()).contains("\"status\":404");
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package sample.actuator.customsecurity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
public class SampleActuatorCustomSecurityApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void homeIsSecure() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("error")).isEqualTo("Unauthorized");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsecureApplicationPath() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/foo", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat((String)body.get("message")).contains("Expected exception in controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsecureStaticResources() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insecureActuator() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/application/status",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secureActuator() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/application/env",
|
||||
Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,10 +18,21 @@ package sample.actuator.log4j2;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleActuatorLog4J2Application {
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(SampleActuatorLog4J2Application.class, args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
endpoints.shutdown.enabled=true
|
||||
|
||||
management.security.enabled=false
|
||||
endpoints.all.web.enabled=true
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package sample.actuator.log4j2;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.Rule;
|
||||
|
|
@ -63,10 +65,17 @@ public class SampleActuatorLog4J2ApplicationTests {
|
|||
|
||||
@Test
|
||||
public void validateLoggersEndpoint() throws Exception {
|
||||
this.mvc.perform(get("/application/loggers/org.apache.coyote.http11.Http11NioProtocol"))
|
||||
this.mvc.perform(get("/application/loggers/org.apache.coyote.http11.Http11NioProtocol")
|
||||
.header("Authorization", "Basic " + getBasicAuth()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(equalTo("{\"configuredLevel\":\"WARN\","
|
||||
+ "\"effectiveLevel\":\"WARN\"}")));
|
||||
}
|
||||
|
||||
private String getBasicAuth() {
|
||||
return new String(Base64.getEncoder()
|
||||
.encode(("user:password").getBytes()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ import java.util.Map;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
|
@ -29,6 +33,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
@Controller
|
||||
public class SampleActuatorUiApplication {
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(Map<String, Object> model) {
|
||||
model.put("message", "Hello World");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,2 @@
|
|||
health.diskspace.enabled=false
|
||||
|
||||
# empty so home page is unsecured
|
||||
security.basic.path=
|
||||
endpoints.all.web.enabled=true
|
||||
|
|
@ -21,9 +21,7 @@ import java.util.Map;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -46,9 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class SampleActuatorUiApplicationPortTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 9010;
|
||||
|
||||
|
|
@ -82,7 +77,7 @@ public class SampleActuatorUiApplicationPortTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ public class SampleActuatorUiApplicationTests {
|
|||
public void testHome() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET,
|
||||
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.exchange("/", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("<title>Hello");
|
||||
|
|
@ -80,11 +81,16 @@ public class SampleActuatorUiApplicationTests {
|
|||
public void testError() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/error",
|
||||
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.exchange("/error",
|
||||
HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(entity.getBody()).contains("<html>").contains("<body>")
|
||||
.contains("Please contact the operator with the above information");
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ import org.springframework.boot.actuate.health.HealthIndicator;
|
|||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties(ServiceProperties.class)
|
||||
|
|
@ -31,6 +35,13 @@ public class SampleActuatorApplication {
|
|||
SpringApplication.run(SampleActuatorApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator helloHealthIndicator() {
|
||||
return new HealthIndicator() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ server.tomcat.accesslog.pattern=%h %t "%r" %s %b
|
|||
security.require-ssl=false
|
||||
#spring.jackson.serialization.INDENT_OUTPUT=true
|
||||
spring.jmx.enabled=true
|
||||
endpoints.all.web.enabled=true
|
||||
|
||||
spring.jackson.serialization.write_dates_as_timestamps=false
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -45,9 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@ActiveProfiles("endpoints")
|
||||
public class EndpointsPropertiesSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
|
|
@ -74,7 +70,7 @@ public class EndpointsPropertiesSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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 sample.actuator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for insecured service endpoints (even with Spring Security on
|
||||
* classpath).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"management.security.enabled:false" })
|
||||
@DirtiesContext
|
||||
@ActiveProfiles("unsecure-management")
|
||||
public class InsecureManagementSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void testHomeIsSecure() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("error")).isEqualTo("Unauthorized");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetrics() throws Exception {
|
||||
try {
|
||||
testHomeIsSecure(); // makes sure some requests have been made
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
// ignore;
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/application/metrics",
|
||||
Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body).containsKey("counter.status.401.unmapped");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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 sample.actuator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for insecured service endpoints (even with Spring Security on
|
||||
* classpath).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"security.basic.enabled:false" })
|
||||
@DirtiesContext
|
||||
public class InsecureSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("message")).isEqualTo("Hello Phil");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,9 +21,7 @@ import java.util.Map;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -47,9 +45,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class ManagementAddressActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 9010;
|
||||
|
||||
|
|
@ -75,7 +70,7 @@ public class ManagementAddressActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -47,9 +46,6 @@ public class ManagementPathSampleActuatorApplicationTests {
|
|||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
@Test
|
||||
public void testHealth() throws Exception {
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
|
|
@ -71,7 +67,7 @@ public class ManagementPathSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.securityProperties.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ import java.util.Map;
|
|||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -46,9 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 9010;
|
||||
|
||||
|
|
@ -98,7 +93,7 @@ public class ManagementPortAndPathSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testErrorPage() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate()
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword())
|
||||
.getForEntity("http://localhost:" + this.port + "/error", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -109,7 +104,7 @@ public class ManagementPortAndPathSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testManagementErrorPage() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword()).getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/error", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -118,7 +113,7 @@ public class ManagementPortAndPathSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ package sample.actuator;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
|
@ -46,9 +46,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class ManagementPortSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 9010;
|
||||
|
||||
|
|
@ -89,7 +86,7 @@ public class ManagementPortSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testErrorPage() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword()).getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/error", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -98,7 +95,7 @@ public class ManagementPortSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -44,9 +43,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class NoManagementSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
|
|
@ -71,7 +67,7 @@ public class NoManagementSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import org.junit.runner.RunWith;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -51,9 +50,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class SampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
|
|
@ -204,7 +200,8 @@ public class SampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testErrorPageDirectAccess() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/error", Map.class);
|
||||
ResponseEntity<Map> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.getForEntity("/error", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
|
|
@ -239,7 +236,7 @@ public class SampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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 sample.actuator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for insecured service endpoints (even with Spring Security on
|
||||
* classpath).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"security.basic.enabled:false", "server.servlet.path:/spring" })
|
||||
@DirtiesContext
|
||||
public class ServletPathInsecureSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/spring/",
|
||||
Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("message")).isEqualTo("Hello Phil");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetricsIsSecure() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate
|
||||
.getForEntity("/spring/application/metrics", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -47,13 +46,11 @@ public class ServletPathSampleActuatorApplicationTests {
|
|||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Test
|
||||
public void testErrorPath() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/spring/error",
|
||||
ResponseEntity<Map> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.getForEntity("/spring/error",
|
||||
Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -84,7 +81,7 @@ public class ServletPathSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
|
|
@ -43,9 +42,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
@DirtiesContext
|
||||
public class ShutdownSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
|
|
@ -73,7 +69,7 @@ public class ShutdownSampleActuatorApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
server.error.path: /oops
|
||||
management.context-path: /admin
|
||||
endpoints.health.sensitive: false
|
||||
management.context-path: /admin
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package sample.secure.oauth2.actuator;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Basic auth security for actuator endpoints.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final SpringBootSecurity springBootSecurity;
|
||||
|
||||
public ActuatorSecurityConfiguration(SpringBootSecurity springBootSecurity) {
|
||||
this.springBootSecurity = springBootSecurity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.requestMatcher(this.springBootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS))
|
||||
.authorizeRequests().antMatchers("/**").authenticated()
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,11 @@ import java.util.UUID;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
|
@ -34,6 +38,13 @@ public class SampleSecureOAuth2ActuatorApplication {
|
|||
return new Message("Hello World");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleSecureOAuth2ActuatorApplication.class, args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
server.port=8081
|
||||
security.basic.enabled=true
|
||||
security.user.password=password
|
||||
endpoints.all.web.enabled=true
|
||||
security.oauth2.resource.id=service
|
||||
security.oauth2.resource.userInfoUri=http://localhost:8080/user
|
||||
logging.level.org.springframework.security=DEBUG
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package sample.secure.oauth2;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("greg").password("turnquist").roles("read");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
spring.datasource.platform=h2
|
||||
|
||||
security.user.name=greg
|
||||
security.user.password=turnquist
|
||||
security.oauth2.client.client-id=foo
|
||||
security.oauth2.client.client-secret=bar
|
||||
security.oauth2.authorization.checkTokenAccess=isAuthenticated()
|
||||
|
|
|
|||
|
|
@ -20,11 +20,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan
|
||||
|
|
@ -34,6 +38,13 @@ public class SampleSecureApplication implements CommandLineRunner {
|
|||
@Autowired
|
||||
private SampleService service;
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
SecurityContextHolder.getContext()
|
||||
|
|
|
|||
|
|
@ -20,15 +20,10 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import sample.secure.SampleSecureApplicationTests.TestConfiguration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
|
@ -43,23 +38,17 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = { SampleSecureApplication.class, TestConfiguration.class })
|
||||
@SpringBootTest(classes = {SampleSecureApplication.class})
|
||||
public class SampleSecureApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SampleService service;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
private Authentication authentication;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
AuthenticationManager authenticationManager = this.context
|
||||
.getBean(AuthenticationManager.class);
|
||||
this.authentication = authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
this.authentication = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
@ -90,9 +79,4 @@ public class SampleSecureApplicationTests {
|
|||
assertThat("Goodbye World").isEqualTo(this.service.denied());
|
||||
}
|
||||
|
||||
@PropertySource("classpath:test.properties")
|
||||
@Configuration
|
||||
protected static class TestConfiguration {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
security.user.password=password
|
||||
|
|
@ -30,11 +30,21 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
|||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
public class SampleServletApplication extends SpringBootServletInitializer {
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Bean
|
||||
public Servlet dispatcherServlet() {
|
||||
|
|
|
|||
|
|
@ -16,15 +16,20 @@
|
|||
|
||||
package sample.servlet;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
|
@ -44,12 +49,11 @@ public class SampleServletApplicationTests {
|
|||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Test
|
||||
public void testHomeIsSecure() throws Exception {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +66,6 @@ public class SampleServletApplicationTests {
|
|||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
return "password";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import java.util.Date;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
|
|
@ -80,7 +80,6 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
|
||||
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
|
|
@ -94,4 +93,25 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
|
|||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Order(1)
|
||||
protected static class ActuatorSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final SpringBootSecurity springBootSecurity;
|
||||
|
||||
public ActuatorSecurity(SpringBootSecurity springBootSecurity) {
|
||||
this.springBootSecurity = springBootSecurity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.requestMatcher(this.springBootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS))
|
||||
.authorizeRequests().anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
spring.thymeleaf.cache: false
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.security: INFO
|
||||
endpoints.all.web.enabled=true
|
||||
|
|
@ -105,8 +105,10 @@ public class SampleMethodSecurityApplicationTests {
|
|||
|
||||
@Test
|
||||
public void testManagementProtected() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.getForEntity("/application/beans", String.class);
|
||||
.exchange("/application/beans", HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@ import java.util.Date;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
|
@ -60,7 +58,6 @@ public class SampleWebSecureCustomApplication implements WebMvcConfigurer {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
|
||||
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -23,10 +23,8 @@ import javax.sql.DataSource;
|
|||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
|
@ -63,7 +61,6 @@ public class SampleWebSecureJdbcApplication implements WebMvcConfigurer {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
|
||||
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ import java.util.Date;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
|
@ -60,12 +59,19 @@ public class SampleWebSecureApplication implements WebMvcConfigurer {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
|
||||
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final SpringBootSecurity springBootSecurity;
|
||||
|
||||
public ApplicationSecurity(SpringBootSecurity springBootSecurity) {
|
||||
this.springBootSecurity = springBootSecurity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin()
|
||||
http.authorizeRequests()
|
||||
.requestMatchers(this.springBootSecurity.staticResources()).permitAll()
|
||||
.anyRequest().fullyAuthenticated().and().formLogin()
|
||||
.loginPage("/login").failureUrl("/login?error").permitAll().and()
|
||||
.logout().permitAll();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
spring.thymeleaf.cache: false
|
||||
security.basic.enabled: false
|
||||
# demo only:
|
||||
security.user.password: password
|
||||
logging.level.org.springframework.security: INFO
|
||||
logging.level.org.springframework.boot.actuate.audit.listener.AuditListener: DEBUG
|
||||
|
|
@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
|
@ -39,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
*/
|
||||
@WebMvcTest
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(properties = { "security.user.password=secret", "debug=true" })
|
||||
@TestPropertySource(properties = { "debug=true" })
|
||||
public class MockMvcSecurityAutoConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
@ -53,7 +54,8 @@ public class MockMvcSecurityAutoConfigurationIntegrationTests {
|
|||
|
||||
@Test
|
||||
public void unauthorizedResponseWithNoUser() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(status().isUnauthorized());
|
||||
this.mockMvc.perform(get("/")
|
||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ package org.springframework.boot.test.autoconfigure.security;
|
|||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
|
@ -30,6 +34,13 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
@SpringBootApplication
|
||||
public class SecurityTestApplication {
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("secret").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class MyController {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.endpoint;
|
||||
|
||||
/**
|
||||
* {@link EndpointPathResolver} implementation that does not support
|
||||
* resolving endpoint paths.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class DefaultEndpointPathResolver implements EndpointPathResolver {
|
||||
|
||||
@Override
|
||||
public String resolvePath(String endpointId) {
|
||||
throw new UnsupportedOperationException("Not supported: Endpoints not available");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -14,24 +14,24 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
|
||||
package org.springframework.boot.endpoint;
|
||||
|
||||
/**
|
||||
* Customizer that can be implemented by beans to configure paths that need to be ignored
|
||||
* by Spring Boot's default Spring Security configuration.
|
||||
* Strategy interface that can be used to resolve endpoint paths
|
||||
* based on endpoint id.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 1.5.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IgnoredRequestCustomizer {
|
||||
public interface EndpointPathResolver {
|
||||
|
||||
/**
|
||||
* Customize the provided {@link IgnoredRequestConfigurer}.
|
||||
* @param configurer the configurer to customize
|
||||
* Resolve endpoint path based on id.
|
||||
*
|
||||
* @param endpointId the endpoint id
|
||||
* @return the resolved path
|
||||
*/
|
||||
void customize(IgnoredRequestConfigurer configurer);
|
||||
String resolvePath(String endpointId);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2012-2017 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
|
||||
*
|
||||
* http://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.boot.endpoint;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
/**
|
||||
* Tests for {@link DefaultEndpointPathResolver}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class DefaultEndpointPathResolverTests {
|
||||
|
||||
private DefaultEndpointPathResolver resolver = new DefaultEndpointPathResolver();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void resolveShouldThrowException() throws Exception {
|
||||
this.thrown.expect(UnsupportedOperationException.class);
|
||||
this.resolver.resolvePath("my-id");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue