Closed peterdnight closed 6 years ago
I'm not sure that I understand how things were working for you with 1.5.x. In 1.5, the security auto-configuration will apply irrespective of whether or not you've declared your own WebSecurityConfigurerAdapter
. If you set my.security.enabled
to true
, you'll get Boot's security and your own security. If you set my.security.enabled
to false
you'll just get Boot's security.
I don't consider what you've done for 2.x to be a workaround. It's one of the approaches that I would recommend. Another that you could consider would be to disable the registration of Spring Security's servlet filter. What's most appropriate really depends on what you're trying to achieve by disabling security.
Scenario: support multiple security settings exclusively through boot configuration: (disabled, in memory, ldap, active directory,...) During desktop development - some times - it is ideal to have as slim a context loaded as possible - hence the disabled option.
In 1.5, I combined my.security.enabled along with spring boot properties: security.basic.enabled , etc. to prevent any security beans from being loaded.
If a single additional ConditionalOnProperty
element is added to SpringBootWebSecurityConfiguration.java - this would enable 0 Spring Security beans to be configured. The reason the workaround is less then ideal is that a lot of beans are getting added into the context.
somthing like: (do this unless?)
@ConditionalOnProperty ( name = "spring.security.disabled", havingValue = "null" )
Adding a property was considered at length in https://github.com/spring-projects/spring-boot/issues/10306. I don't think anything's happened since then to change my opinion. Have you considered disabling the auto-configuration using the spring.autoconfigure.exclude
property?
I found this issue after adding the exclude. While the bean does not get constructed, the WebSecurityConfigurerAdapter
is detected as being present and the boot security initialization proceeds.
I actually debugged this by having a single class unit test (shown below) - using a very slim context @SpringBootApplication
- and found that none of the SpringSecurity
classes are loaded with the exclude added.
Having any bean - even if not instantiated - but extending WebSecurityConfigurerAdapter
- causes SpringBoot initialization of security beans, regardless of the exclude:
@Configuration
@ConditionalOnProperty ( "my.security.enabled" )
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
<working config>
}
Test class to validate working exclude - not no beans extending WebSecurityConfigurerAdapter are present:
@RunWith ( SpringRunner.class )
@SpringBootTest ( classes = A_Simple_Application.Simple_Application.class , webEnvironment = WebEnvironment.RANDOM_PORT )
@ActiveProfiles ( "junit" )
@DirtiesContext
public class A_Simple_Application {
final static private Logger logger = LoggerFactory.getLogger( A_Simple_Application.class );
@BeforeClass
// @Before
static public void setUpBeforeClass ()
throws Exception {
System.out.println( "Starting logging" );
CsapTest.initialize( logger.getName() );
}
@Autowired
private ApplicationContext applicationContext;
/**
*
* Simple test app that excludes security autoconfiguration
* ManagementWebSecurityAutoConfiguration.class
*/
@SpringBootApplication ( exclude = {
SecurityAutoConfiguration.class
} )
public static class Simple_Application {
@RestController
static public class Hello {
@GetMapping ( "/hi" )
public String hi () {
return "Hello" +
LocalDateTime.now()
.format( DateTimeFormatter
.ofPattern( "HH:mm:ss, MMMM d uuuu " ) );
}
@Inject
ObjectMapper jsonMapper;
}
}
@Test
public void load_context () {
logger.info( CsapTest.TC_HEAD );
logger.info( "beans loaded: {}", applicationContext.getBeanDefinitionCount() );
assertThat( applicationContext.getBeanDefinitionCount() )
.as( "Spring Bean count" )
.isGreaterThan( 200 );
// Assert.assertFalse( true);
}
@LocalServerPort
private int testPort;
@Inject
RestTemplateBuilder restTemplateBuilder;
@Test
public void http_get_hi_from_simple_app ()
throws Exception {
String simpleUrl = "http://localhost:" + testPort + "/hi";
logger.info( CsapTest.TC_HEAD + "hitting url: {}", simpleUrl );
// mock does much validation.....
TestRestTemplate restTemplate = new TestRestTemplate( restTemplateBuilder );
ResponseEntity<String> response = restTemplate.getForEntity( simpleUrl, String.class );
logger.info( "result:\n" + response );
assertThat( response.getBody() )
.startsWith( "Hello" );
}
}
Sorry, I don't understand your latest comment.
and found that none of the SpringSecurity classes are loaded with the exclude added.
That's what I would expect. With Boot's auto-configuration excluded Security is not configured unless you do so yourself. That's what you want to happen, isn't it?
While the bean does not get constructed, the WebSecurityConfigurerAdapter is detected as being present and the initialization proceeds.
I don't understand what you're referring to here. The initialisation of what proceeds?
Rather than pasting code (that doesn't compile) into an issue comment, perhaps you could provide an attachment or repository on GitHub that precisely illustrates the problem without requiring any modification?
Thanks for suggestions and links. After playing with the exclude option - desired behavior is occurring. I switched to the following convention, to enable security to be completely configuration driven using a single property. I was concerned that there would be potential for ordering issues - but my unit tests are all passing.
@SpringBootApplication ( exclude = {SecurityAutoConfiguration.class} )
@Import(MySecurityConfiguration.class)
public class MyApplication{
}
Then in my security configuration:
@Configuration
@ConditionalOnProperty ( "my.security.enabled" )
@Import ( SecurityAutoConfiguration.class
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {
}
Excellent. Thanks for following up.
FWIW, worked a similar solution using profiles for configuring secure
and insecure
profiles.
The secure
profile loads OAUTH2 config from environment variables for real operation. The insecure
profile skips auth for integration tests with an external service.
Put it all in a demo repo here: https://github.com/deftinc/spring_azure_ad_profile/
Overall - I really like/prefer the new 2.0 security integration. The only issue is how can security be enabled/disabled via configuration.
In 1.5.x - security could be enabled / disabled via property. Unfortunately
@ConditionalOnProperty
seems to keep class available , so the new SpringBootWebSecurityConfiguration,@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
seems to find it any way, and configures default settings (http basic, everything protected, etc).While debugging - I removed the @Configuration from MySecurityConfiguration , and security was not applied. So if there is some conditional way to @Import the file - that might also work.
Suggestions appreciated, Peter
Works in 1.5.x:
Workaround for 2.x: Add an additional configuration with ! property, and ignore all
Spring default handler: