Extract actuator security into separate classes
So spring-security + a web app is secure by default (you don't need the actuator).
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class AuthenticationManagerConfiguration {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(AuthenticationManagerConfiguration.class);
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private List<SecurityPrequisite> dependencies;
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(
|
||||
ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
|
||||
|
||||
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> builder = new AuthenticationManagerBuilder(
|
||||
objectPostProcessor).inMemoryAuthentication();
|
||||
User user = this.security.getUser();
|
||||
|
||||
if (user.isDefaultPassword()) {
|
||||
logger.info("\n\nUsing default password for application endpoints: "
|
||||
+ user.getPassword() + "\n\n");
|
||||
}
|
||||
|
||||
// TODO: Add the management role...
|
||||
Set<String> roles = new LinkedHashSet<String>(user.getRole());
|
||||
|
||||
builder.withUser(user.getName()).password(user.getPassword())
|
||||
.roles(roles.toArray(new String[roles.size()]));
|
||||
|
||||
return builder.and().build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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 javax.servlet.Filter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
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.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.AnyRequestMatcher;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-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)</code> but can easily be customized by providing a bean definition
|
||||
* of type {@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} this configuration.</li>
|
||||
* <li>Switch off security temporarily (e.g. for a dev environment): set
|
||||
* <code>security.basic.enabled: false</code></li>
|
||||
* <li>Customize the user details: add an AuthenticationManager bean</li>
|
||||
* <li>Add form login for user facing resources: add a
|
||||
* {@link WebSecurityConfigurerAdapter} and use {@link HttpSecurity#formLogin()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
@ConditionalOnClass({ EnableWebSecurity.class })
|
||||
@ConditionalOnMissingBean(annotation = EnableWebSecurity.class)
|
||||
public class SecurityAutoConfiguration {
|
||||
|
||||
private static List<String> DEFAULT_IGNORED = Arrays.asList("/css/**", "/js/**",
|
||||
"/images/**", "/**/favicon.ico");
|
||||
|
||||
@Bean(name = "org.springframework.autoconfigure.security.SecurityProperties")
|
||||
@ConditionalOnMissingBean
|
||||
public SecurityProperties securityProperties() {
|
||||
return new SecurityProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AuthenticationEventPublisher authenticationEventPublisher() {
|
||||
return new DefaultAuthenticationEventPublisher();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ IgnoredPathsWebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnBean(annotation = EnableWebSecurity.class)
|
||||
public SecurityConfigurer<Filter, WebSecurity> ignoredPathsWebSecurityConfigurerAdapter() {
|
||||
return new IgnoredPathsWebSecurityConfigurerAdapter();
|
||||
}
|
||||
|
||||
// Get the ignored paths in early
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
private static class IgnoredPathsWebSecurityConfigurerAdapter implements
|
||||
SecurityConfigurer<Filter, WebSecurity> {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(WebSecurity builder) throws Exception {
|
||||
IgnoredRequestConfigurer ignoring = builder.ignoring();
|
||||
List<String> ignored = getIgnored(this.security);
|
||||
ignoring.antMatchers(ignored.toArray(new String[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean({ ApplicationWebSecurityConfigurerAdapter.class })
|
||||
@ConditionalOnExpression("${security.basic.enabled:true}")
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 5)
|
||||
protected static class ApplicationWebSecurityConfigurerAdapter extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private AuthenticationEventPublisher authenticationEventPublisher;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
if (this.security.isRequireSsl()) {
|
||||
http.requiresChannel().anyRequest().requiresSecure();
|
||||
}
|
||||
|
||||
String[] paths = getSecureApplicationPaths();
|
||||
if (this.security.getBasic().isEnabled() && paths.length > 0) {
|
||||
http.exceptionHandling().authenticationEntryPoint(entryPoint());
|
||||
http.requestMatchers().antMatchers(paths);
|
||||
http.authorizeRequests()
|
||||
.anyRequest()
|
||||
.hasAnyRole(
|
||||
this.security.getUser().getRole().toArray(new String[0])) //
|
||||
.and().httpBasic() //
|
||||
.and().anonymous().disable();
|
||||
}
|
||||
if (!this.security.isEnableCsrf()) {
|
||||
http.csrf().disable();
|
||||
}
|
||||
// No cookies for application endpoints by default
|
||||
http.sessionManagement().sessionCreationPolicy(this.security.getSessions());
|
||||
|
||||
SecurityAutoConfiguration.configureHeaders(http.headers(),
|
||||
this.security.getHeaders());
|
||||
|
||||
}
|
||||
|
||||
private String[] getSecureApplicationPaths() {
|
||||
List<String> list = new ArrayList<String>();
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
AuthenticationManager manager = super.authenticationManager();
|
||||
if (manager instanceof ProviderManager) {
|
||||
((ProviderManager) manager)
|
||||
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(AuthenticationManager.class)
|
||||
protected static class ApplicationAuthenticationManagerConfiguration extends
|
||||
AuthenticationManagerConfiguration {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
if (headers.isXss()) {
|
||||
configurer.xssProtection();
|
||||
}
|
||||
if (headers.isCache()) {
|
||||
configurer.cacheControl();
|
||||
}
|
||||
if (headers.isFrame()) {
|
||||
configurer.frameOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getIgnored(SecurityProperties security) {
|
||||
List<String> ignored = new ArrayList<String>(security.getIgnored());
|
||||
if (ignored.isEmpty()) {
|
||||
ignored.addAll(DEFAULT_IGNORED);
|
||||
}
|
||||
else if (ignored.contains("none")) {
|
||||
ignored.remove("none");
|
||||
}
|
||||
return ignored;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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;
|
||||
|
||||
/**
|
||||
* Marker interface for beans that need to be initialized before any security
|
||||
* configuration is evaluated.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface SecurityPrequisite {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.UUID;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Properties for the security aspects of an application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConfigurationProperties(name = "security", ignoreUnknownFields = false)
|
||||
public class SecurityProperties implements SecurityPrequisite {
|
||||
|
||||
private boolean requireSsl;
|
||||
|
||||
// Flip this when session creation is disabled by default
|
||||
private boolean enableCsrf = false;
|
||||
|
||||
private Basic basic = new Basic();
|
||||
|
||||
private Headers headers = new Headers();
|
||||
|
||||
private SessionCreationPolicy sessions = SessionCreationPolicy.STATELESS;
|
||||
|
||||
private List<String> ignored = new ArrayList<String>();
|
||||
|
||||
private User user = new User();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void setBasic(Basic basic) {
|
||||
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<String>(ignored);
|
||||
}
|
||||
|
||||
public List<String> getIgnored() {
|
||||
return this.ignored;
|
||||
}
|
||||
|
||||
public static class Headers {
|
||||
|
||||
public static enum HSTS {
|
||||
none, domain, all
|
||||
}
|
||||
|
||||
private boolean xss;
|
||||
|
||||
private boolean cache;
|
||||
|
||||
private boolean frame;
|
||||
|
||||
private boolean contentType;
|
||||
|
||||
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 HSTS getHsts() {
|
||||
return this.hsts;
|
||||
}
|
||||
|
||||
public void setHsts(HSTS hsts) {
|
||||
this.hsts = hsts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Basic {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private String realm = "Spring";
|
||||
|
||||
private String[] path = new String[] { "/**" };
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
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 static class User {
|
||||
|
||||
private String name = "user";
|
||||
|
||||
private String password = UUID.randomUUID().toString();
|
||||
|
||||
private List<String> role = new ArrayList<String>(Arrays.asList("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 boolean isDefaultPassword() {
|
||||
return this.defaultPassword;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.Test;
|
||||
import org.springframework.boot.TestUtils;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInitializer;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecurityAutoConfiguration}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SecurityAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void testWebConfiguration() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
debugRefresh(this.context);
|
||||
assertNotNull(this.context.getBean(AuthenticationManager.class));
|
||||
// 4 for static resources and one for the rest
|
||||
assertEquals(5, this.context.getBean(FilterChainProxy.class).getFilterChains()
|
||||
.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableIgnoredStaticApplicationPaths() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
TestUtils.addEnviroment(this.context, "security.ignored:none");
|
||||
this.context.refresh();
|
||||
// Just the application endpoints now
|
||||
assertEquals(1, this.context.getBean(FilterChainProxy.class).getFilterChains()
|
||||
.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableBasicAuthOnApplicationPaths() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
TestUtils.addEnviroment(this.context, "security.basic.enabled:false");
|
||||
this.context.refresh();
|
||||
// No security at all not even ignores
|
||||
assertEquals(0, this.context.getBeanNamesForType(FilterChainProxy.class).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideAuthenticationManager() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(TestConfiguration.class, SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertEquals(this.context.getBean(TestConfiguration.class).authenticationManager,
|
||||
this.context.getBean(AuthenticationManager.class));
|
||||
}
|
||||
|
||||
private static AnnotationConfigWebApplicationContext debugRefresh(
|
||||
AnnotationConfigWebApplicationContext context) {
|
||||
TestUtils.addEnviroment(context, "debug:true");
|
||||
LoggingApplicationContextInitializer logging = new LoggingApplicationContextInitializer();
|
||||
logging.initialize(context);
|
||||
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
|
||||
initializer.initialize(context);
|
||||
context.refresh();
|
||||
initializer.onApplicationEvent(new ContextRefreshedEvent(context));
|
||||
return context;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestConfiguration {
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager myAuthenticationManager() {
|
||||
this.authenticationManager = new AuthenticationManager() {
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return new TestingAuthenticationToken("foo", "bar");
|
||||
}
|
||||
};
|
||||
return this.authenticationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.bind.RelaxedDataBinder;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecurityProperties}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SecurityPropertiesTests {
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredSingleValued() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.ignored", "/css/**")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertEquals(1, security.getIgnored().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredEmpty() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.setConversionService(new DefaultConversionService());
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.ignored", "")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertEquals(0, security.getIgnored().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredDisable() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.setConversionService(new DefaultConversionService());
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.ignored", "none")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertEquals(1, security.getIgnored().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredMultiValued() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.setConversionService(new DefaultConversionService());
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.ignored", "/css/**,/images/**")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertEquals(2, security.getIgnored().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingIgnoredMultiValuedList() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.setConversionService(new DefaultConversionService());
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("security.ignored[0]", "/css/**");
|
||||
map.put("security.ignored[1]", "/foo/**");
|
||||
binder.bind(new MutablePropertyValues(map));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertEquals(2, security.getIgnored().size());
|
||||
assertTrue(security.getIgnored().contains("/foo/**"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutogeneratedIfUnresolovedPlaceholder() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.user.password", "${ADMIN_PASSWORD}")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertTrue(security.getUser().isDefaultPassword());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPasswordAutogeneratedIfEmpty() {
|
||||
SecurityProperties security = new SecurityProperties();
|
||||
RelaxedDataBinder binder = new RelaxedDataBinder(security, "security");
|
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap(
|
||||
"security.user.password", "")));
|
||||
assertFalse(binder.getBindingResult().hasErrors());
|
||||
assertTrue(security.getUser().isDefaultPassword());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user