I'm using spring security.
I have this scenario:
create 2 users
login with the first and login again with the second before the session of user 1 expires
The correct behavior is that the first session is set expired and anew session is created.
Which spring security part is in charge of doing the expiration and creation of new session? the success handler/ authentication provider?
I presume this is what you are looking for, if not, please let me know, I will delete my answer. You need something for session management. I have the XML code this way.
<security:session-management session-fixation-protection="migrateSession">
<security:concurrency-control session-registry-ref="sessionRegistry" max-sessions="1" expired-url="/login"/>
</security:session-management>
Also the class below for sessionRegistry :
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().maximumSessions(-1).sessionRegistry(sessionRegistry());
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
Instead of migrateSession, you can use newSession, that way, old session will be automatically expired and a fresh one will be created.
Related
I'm learning about Spring Security in a Spring Boot app and I have a very simple example. And I see that if I comment the configure(AuthenticationManagerBuilder auth) there is no difference. If I use it or not I have the same output, and I need to login with the hardcoded credentials.
#Configuration
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// private final MyUserDetailsService myUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
// #Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(myUserDetailsService);
// }
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
MyUserDetailsService class:
#Service
public class MyUserDetailsService implements UserDetailsService {
private static final String USERNAME = "john";
private static final String PASSWORD = "$2a$10$fDDUFA8rHAraWnHAERMAv.4ReqKIi7mz8wrl7.Fpjcl1uEb6sIHGu";
#Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
if (!userName.equals(USERNAME)) {
throw new UsernameNotFoundException(userName);
}
return new User(USERNAME, PASSWORD, new ArrayList<>());
}
}
RestController:
#RestController
public class HelloController {
#GetMapping("/hello")
public String hello() {
return "Hello World!";
}
}
I want to know if implementing the UserDetailsService interface is equivalent with overriding the configure(AuthenticationManagerBuilder auth). Thank you!
UserDetailsService
UserDetailsService is used by DaoAuthenticationProvider for retrieving
a username, password, and other attributes for authenticating with a
username and password. Spring Security provides in-memory and JDBC
implementations of UserDetailsService.
You can define custom authentication by exposing a custom
UserDetailsService as a bean. For example, the following will
customize authentication assuming that CustomUserDetailsService
implements UserDetailsService
The UserDetailsService interface is used to retrieve user-related data. It has one method named loadUserByUsername() which can be overridden to customize the process of finding the user. In order to provide our own user service, we will need to implement the UserDetailsService interface.
loadUserByUsername(String username) returns the UserDetails which is part of org.springframework.security.core.userdetails which consists of getUsername(), getPassword(), getAuthorities() methods which is used further for spring security.
We can also customize the org.springframework.security.core.userdetails.User (here used as new User(USERNAME, PASSWORD, new ArrayList<>())) by implemeting the UserDetails interface.
Here, I am sharing the ideal way to use the UserDetailsService service
#Component("userDetailsService")
public class DomainUserDetailsService implements UserDetailsService {
private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
private final UserRepository userRepository;
public DomainUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
#Transactional
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
if (new EmailValidator().isValid(login, null)) {
return userRepository.findOneWithAuthoritiesByEmailIgnoreCase(login)
.map(user -> createSpringSecurityUser(login, user))
.orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
}
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin)
.map(user -> createSpringSecurityUser(lowercaseLogin, user))
.orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));
}
private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
if (!user.getActivated()) {
throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
}
List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
.map(authority -> new SimpleGrantedAuthority(authority.getName()))
.collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
grantedAuthorities);
}
}
when loadUserByUsername is invoked?
As described above, It is typically called by DaoAuthenticationProvide instance in order to authenticate a user. For example, when a username and password is submitted, a UserdetailsService is called to find the password for that user to see if it is correct. It will also typically provide some other information about the user, such as the authorities and any custom fields you may want to access for a logged in user (email, for instance)
In-Memory Authentication
Here you have used the static values for username and password which can be ideally configured using the In-Memory Authentication as follow.
Spring Security’s InMemoryUserDetailsManager implements UserDetailsService to provide support for username/password based authentication that is retrieved in memory. InMemoryUserDetailsManager provides management of UserDetails by implementing the UserDetailsManager interface. UserDetails based authentication is used by Spring Security when it is configured to accept a username/password for authentication.
#Bean
public UserDetailsService users() {
UserDetails user = User.builder()
.username("user")
.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
configure(AuthenticationManagerBuilder auth)
This method uses AuthenticationManagerBuilder which internally use SecurityBuilder to create an AuthenticationManager. Allows for easily building in memory authentication, LDAP authentication, JDBC based authentication, adding UserDetailsService, and adding
AuthenticationProvider.
How Spring Security add/configure AuthenticationManagerBuilder?
UserDetailsService interface is equivalent with overriding the
configure(AuthenticationManagerBuilder auth)
No
No, it's not same.
User details service provided in the application as bean is registered with global authentication manager (details) and is fallback for all the local authentication manager.
Depending on application set up can have multiple local authentication managers. Each local authentication manager will use the default user details service configured with configure(AuthenticationManagerBuilder auth).
When should I override the configure(AuthenticationManagerBuilder
auth) from Spring Security in a Spring Boot app?
You should override if you have different authorization/authentication requirements and would you like to plugin your own authentication provider to satisfy the requirement or add any built in provider like ldap and in memory providers. You can also do it directly using http security bean shown below.
All the authentication providers are added to Provider Manager and are tried until one is found.
By default without providing anything ( i.e. without user details service or without overriding authentication manager ) you would have the default global authentication manager with auto configured user details manager ( i.e user password InMemoryUserDetailsManager implementation as configured in UserDetailsServiceAutoConfiguration auto configuration ).
So when you provide user details service application bean the auto configuration backs off and now your global authentication manager now is configured with the provided bean.
More details here
Here is the good explanation how it all comes together.
I would also like to expand little bit more on spring security authentication manager in general which is very easy to overlook.
As I previously noted there is global authentication manager and local authentication managers. There is special care to be taken when configuring each if needed.
This is explained in the java doc for the global authentication manager annotation.
The EnableGlobalAuthentication annotation signals that the annotated
class can be used to configure a global instance of
AuthenticationManagerBuilder.
For example:
#Configuration
#EnableGlobalAuthentication
public class MyGlobalAuthenticationConfiguration {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
.and().withUser("admin").password("password").roles("USER", "ADMIN");}}
Annotations that are annotated with EnableGlobalAuthentication also signal that the annotated class can be
used to configure a global instance of AuthenticationManagerBuilder.
For example:
#Configuration
#EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
.and().withUser("admin").password("password").roles("USER", "ADMIN");
}
// Possibly overridden methods ... }
The following annotations are annotated with EnableGlobalAuthentication
EnableWebSecurity EnableWebMvcSecurity EnableGlobalMethodSecurity
Configuring AuthenticationManagerBuilder in a class without the
EnableGlobalAuthentication annotation has unpredictable results.
EnableGlobalAuthentication imports configuration AuthenticationConfiguration responsible for setting up the default configuration for global authentication manager.
AuthenticationConfiguration configures two key pieces to make the authentication manager - user details and authentication provider.
User details is configured using InitializeUserDetailsBeanManagerConfigurer and authentication provider is configured using InitializeAuthenticationProviderBeanManagerConfigurer. Both of required beans are looked up in application context - that is how your user detail service is registered with global authentication manager.
GlobalMethodSecurityConfiguration and WebSecurityConfigurerAdapter are consumers of global authentication managers.
WebSecurityConfigurerAdapter can be used to create and configure local authentication manager (add new authentication providers) and also typically used to have different authentication/authorization requirements in application like mvc vs rest and public vs admin endpoints.
With spring security alone #EnableWebSecurity triggers the above flow as part of spring security filter chain set up. With spring boot the same flow is triggered by spring security auto configuration.
In spring security 5.4 version you can define http security as beans without needing to extend WebSecurityConfigurerAdapter class. Spring boot will have support for this in 2.4.0 release. More details here
#Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception
{
http
.authenticationProvider(custom authentication provider)
.userDetailsService( custom user details service)
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
You are using the #Service annotation which creates the bean of the UserDetailsService at the time of the component scan. There is no need to specify it again in the AuthenticationManagerBuilder.
If you don't use the #Service annotation, then you can configure it manually in the WebSecurityConfigurerAdapter by over-riding the AuthenticationManagerBuilder.
To switch off the default web application security configuration completely you can add a bean with #EnableWebSecurity as explained in the spring boot documentation (section 4.10.1. MVC Security),
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(MyAuthenticationProvider);
}
}
The #EnableWebSecurity is a marker annotation. It allows Spring to find (it's a #Configuration and, therefore, #Component) and automatically apply the class to the global WebSecurity
To switch off the default web application security configuration completely you can add a bean with #EnableWebSecurity (this does not disable the authentication manager configuration or Actuator’s security). To customize it you normally use external properties and beans of type WebSecurityConfigurerAdapter (e.g. to add form-based login).
...
If you add #EnableWebSecurity and also disable Actuator security, you will get the default form-based login for the entire application unless you add a custom WebSecurityConfigurerAdapter.
...
If you define a #Configuration with #EnableWebSecurity anywhere in your application it will switch off the default webapp security settings in Spring Boot (but leave the Actuator’s security enabled). To tweak the defaults try setting properties in security.* (see SecurityProperties for details of available settings) and SECURITY section of Common application properties.
No, implementing the UserDetailsService interface is not equivalent to overriding the configure(AuthenticationManagerBuilder auth).
If you override UserDetailsSeervice and verify the username and password by override loadUserByUsername(), in your case it is static values(I would recommend for static users use inMemoryAuthentication).
You need to Autowired UserDetailsService
#Autowired
UserDetailsService userDetailsService;
And
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
this will tell your authenticationManager to use userDetailsService which is been implemented for authentication.
I want to know if implementing the UserDetailsService interface is equivalent with overriding the configure(AuthenticationManagerBuilder auth).
No, they are not comparable.
UserDetailsService is core interface which loads user-specific data. It is used throughout the framework as a user DAO and is the strategy used by the DaoAuthenticationProvider. *
and
AuthenticationManagerBuilder allows for easily building in memory authentication, JDBC based authentication, adding UserDetailsService, and adding AuthenticationProvider's.
So it is evident that when you use UserDetailsService, it means you are using DaoAuthenticationProvider for fetching user details from your underlying database.
NOTE: AuthenticationProvider is an abstraction for fetching user information from different sources/repositories and validates if the retrieved information is similar to the one provided by users.
Let's see an example, the configuration looks like this:
#Autowired
YourUserDetailServiceImpl userDetailsService;
.....
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
...
#Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); //a provider
provider.setUserDetailsService(userDetailsService); //user details service
provider.setPasswordEncoder(encoder()); //you can add password encoders too
return provider;
}
And YourUserDetailServiceImpl has to override loadUserByUsername() to fetch used details.
#Override
public UserDetails loadUserByUsername(String email) {
final Account acc = accRepository.findByEmail(email);
if (acc == null)
throw new UsernameNotFoundException("Account not found");
//this can be a custom Object of your choice that `extends User`
return new UserPrincipal(
acc.getEmail(),
acc.getPassword(),
acc.isEnabled(),
true, true, true,
acc.getEpsRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList()));
}
I'm working on a Spring project. The functionality is already done. What's missing is the security context.
As my project (maven) is separated in different sub projects (Services, RestControllers, Domain), I want the security configuration to be a separate sub project as well, which I only have to add as dependency to the main app to activate it.
I started with a very basic configuration, which is, by now, the only class in the security sub project:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password("admin1")
.roles("ADMIN", "USER");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/").permitAll().and().authorizeRequests().anyRequest().authenticated();
}
}
As soon as I add this project as dependency to my main app, the security context is obviously getting activated, as the default spring login dialogue pops up. The thing is, that Spring ignores the configuration which I've defined in the SecurityConfiguration. It even won't let me access '/', or neither it let's me login with the defined user. Checking in debug mode, it never runs through the public void configure(AuthenticationManagerBuilder auth) method.
In a nut shell:
It activates the spring security context, but it does not apply my configuration. Why is that?
In case of Spring MVC project with Java based configuration import SecurityConfiguration to your ApplicationConfiguration
#EnableWebMvc
#Configuration
#ComponentScan({"xx.xxx.xx.*"})
#PropertySource("classpath:xxx.properties")
#Import(value = {SecurityConfiguration.class}) // <= like this
public class ApplicationConfiguration extends WebMvcConfigurerAdapter { ... }
You may also need SecurityInitializer. This class has to be present even though it's empty. This is a good place for certain filters that must be executed before security configuration.
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { }
Might be a newbie question. I want to inject CustomAuthenticationProviderInside Spring AuthenticationManager. I found a lot of examples online doing that:
<authentication-manager>
<authentication-provider ref="CustomAuthenticationProvider"/>
</authentication-manager>
How can I do that using Java Config class?
Spring offers one default implementation of AuthenticationManager which is ProviderManager. ProviderManager has a constructor which takes an array of Authentication providers
public ProviderManager(List<AuthenticationProvider> providers) {
this(providers, null);
}
If you want you can just play with it by extending ProviderManager
public class MyAuthenticationManager extends ProviderManager implements AuthenticationManager{
public MyAuthenticationManager(List<AuthenticationProvider> providers) {
super(providers);
providers.forEach(e->System.out.println("Registered providers "+e.getClass().getName()));
}
}
And then i Java security configuration you can add your custom authentication manager.
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return new MyAuthenticationManager(Arrays.asList(new CustomAuthenticationProvider()));
}
I've got a spring boot application that uses oauth2 for authentication.
The oauth2 mechanism is working and clients can authenticate and receive their access tokens.
I want to secure the actuators endpoints with httpbasic authentication, i.e. not requiring the user to first use oauth2 for authentication and then access the actuator endpoints.
What i've done so far is to set the following in properties file:
management.context-path=/admin/actuators
management.security.enabled=true
management.security.role=ADMIN
security.user.name=admin
security.user.password=password
I've tried various ways to set configuration with a ResourceServerConfigurerAdapter and WebSecurityConfigurerAdapter.
None of my attempts are working and it keeps on telling me
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
What is the correct way to get OAUTH2 and the management endpoint to work?
The problem is that #EnableResourceServer imports ResourceServerConfiguration, which has an order of 3, far superior to ManagementServerProperties.ACCESS_OVERRIDE_ORDER.
See Spring Boot documentation on actuator security and ordering config classes : http://docs.spring.io/spring-boot/docs/1.4.3.RELEASE/reference/htmlsingle/#boot-features-security-actuator
The default actuator security config is a lot more clever than just allowing access to the /health endpoint and blocking the rest, it actually changes depending on management.port and management.contextPath, and it can get pretty hard to find the correct management endpoint URLs without leaving gaping holes in your security or messing with your own resources.
If you want to keep the benefit of the autoconfigured management security, two options :
EDIT : a) Lower ResourceServerConfiguration order using a BeanPostProcessor
This improvement has been suggested by #dsyer on the github thread :
#Component
#Slf4j
public class ResourceServerConfigurationPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ResourceServerConfiguration) {
LOGGER.debug("Lowering order of ResourceServerConfiguration bean : {}", beanName);
ResourceServerConfiguration config = (ResourceServerConfiguration) bean;
config.setOrder(SecurityProperties.ACCESS_OVERRIDE_ORDER);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
I just replaced my code below with this class, and it works perfectly.
EDIT : b) Manually overriding ResourceServerConfiguration order
If you don't like post processors for some reason, you can replace the #EnableResourceServer with another configuration class whose order will come after the default management security :
/**
* Extend the default resource server config class, and downgrade its order
*/
public class ResourceServerLowPrecedenceConfiguration extends ResourceServerConfiguration {
/**
* This is enough to override Spring Boot's default resource security,
* but it does not takes over the management.
*/
#Override
public int getOrder() {
return SecurityProperties.ACCESS_OVERRIDE_ORDER;
}
}
And your own configuration class :
/** #EnableResourceServer is replaced by #Import using the low precedence config */
#Configuration
#Import(ResourceServerLowPrecedenceConfiguration.class)
public class YourOwnOAuth2Config extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
// Secure your resources using OAuth 2.0 here
}
}
EDIT : You can also rewrite your own #EnableResourceServer annotation to shortcut the #Import :
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Import(ResourceServerLowPrecedenceConfiguration.class)
public #interface EnableResourceServer {
}
IMHO this should be the default behavior when spring-security-oauth is on the classpath.
See discussion on GitHub issue :
https://github.com/spring-projects/spring-boot/issues/5072
Ok, got it to work using the following java config.
The endpoint, /admin/actuators/health, is accessible by anyone and all other /admin/actuators/* endpoints are authenticated.
#Configuration
#Order(1)
protected static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/admin/actuators/health").permitAll()
.and()
.antMatcher("/admin/actuators/**")
.authorizeRequests()
.anyRequest()
.hasRole("ADMIN")
.and()
.httpBasic();
}
}
security.oauth2.resource.filter-order = 3 in application.yml will do the trick
With Spring-Security you can have Multiple HttpSecurity configuration.
<http pattern="/actuators/**/*" request-matcher="ant" authentication-manager-ref="basicAuthManager">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<http-basic />
<http>
<http use-expressions="false">
... your oauth config
</http>
<authentication-manager id="basicAuthManager">
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
... your oath config stuff
(I prefere xml, but you can do this with java config too)
#See http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#nsa-http
(But think that you could not do this by plain spring-boot configuration.)
I have, what I think is, a very simple and basic setup for locally running a Spring Boot webapp with some authentication.
I would expect that when I run this application through Spring Boot, that my custom security settings would override the default behavior when I specify the local profile.
mvn -Dspring.profiles.active="local" spring-boot:run
Maybe I'm specifying the profiles.active wrong, but when the app runs, it still spits out a generated password to use, and doesn't seem to allow any access to the /login path without said authentication.
I'm also not seeing the active profiles under /env either, which may be a little telling.
I have a WebSecurityConfigurer overridden like so:
#Configuration
#EnableWebSecurity
#Profile("local")
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN", "USER")
.and().withUser("user").password("user").roles("USER");
}
}
My main #Configuration class is your standard Spring Java-style base config:
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I think I ran into the same issue. I wanted to use Spring profiles to select between none, basic, form, etc. auth. However, if I put the #Profile, #Configuration, and #EnableWebMvcSecurity on the public class WebSecurityConfig extends WebSecurityConfigurerAdapter class, like they show in the examples, basic auth was active at times when I wanted no auth. (This is with #SpringBootApplication on my Application class.
I achieved what I wanted with making beans out of WebSecurityConfigurerAdapter, instead of #Configurations (code snippet is in Groovy):
#Configuration
#EnableWebMvcSecurity
class SecurityConfig {
#Bean
#Profile('no-auth')
WebSecurityConfigurerAdapter noAuth() {
new WebSecurityConfigurerAdapter() {
#Override
void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
}
}
}
#Bean
#Profile('default')
WebSecurityConfigurerAdapter basic() {
new WebSecurityConfigurerAdapter() {
#Override
void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers('/').permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
}
}
Second attempt to provide better control of security settings. What's the high level options for controlling security auto configuration:
Switch off security completely and permanently:
remove Spring Security from the classpath
or exlude security auto config - #EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
Switch off default basic auth security by setting security.basic.enabled=false
It is pretty easy to control different security settings if you have a total control of how security settings, security auto configuration and spring profiles are used.
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
#Configuration
public class WebSecurityConfig {
#Configuration
#EnableAutoConfiguration(exclude = SecurityAutoConfiguration.class)
#ConditionalOnExpression("!${my.security.enabled:false}")
protected static class DefaultWebSecurityConfig {
}
#Configuration
#EnableAutoConfiguration
#EnableWebMvcSecurity
#Profile("local")
#ConditionalOnExpression("${my.security.enabled:false}")
protected static class LocalWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated();
http
.formLogin().loginPage("/login").permitAll().and()
.logout().permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
}
In above classes I basically removed #EnableAutoConfiguration from Application class order to use it conditionally. Created two config classes, DefaultWebSecurityConfig and LocalWebSecurityConfig which are chosen by my.security.enabled flag using a Boot #ConditionalOnExpression.
First config simply excludes SecurityAutoConfiguration if my security is not enabled. Second one enabled security and uses local profile. By creating yet another config with a different profile you can control what happens with different profiles. Then you could choose if security is enabled and which profile is used:
#java -jar build/libs/gs-securing-web-0.1.0.jar
#java -jar build/libs/gs-securing-web-0.1.0.jar --spring.profiles.active=local --my.security.enabled=true
If you have an option to use application.yml, different settings could be automatically applied per profile still defining a default values. This would be good if you just want to disable default basic authentication enabled by default security auto config.
security:
basic:
enabled: false
---
spring:
profiles: local
security:
basic:
enabled: true
---
There are probably a million different ways to do these and it's always case by case which works best for current use case.
maven will spawn a new process to run a boot app and it doesn't inherit your -Dspring.profiles.active="local" which you passed to mvn command itself.
Why don't you just build the boot fat jar and then run it manually as an executable jar and then you can control what command line parameters you pass to your program.
Other than that, Spring Boot reference doc mentions in a security chapter:
If Spring Security is on the classpath then web applications will be secure by default with “basic” authentication on all HTTP endpoints.
So I just tried this with Securing a Web Application Guide and if I added what you wrote in your question, app defaults to basic authentication when using a profile which is not active.
#EnableAutoConfiguration allows you to define excludes for autoconfiguration classes, but you need to find a way to disable this together with a profile. So possibly wrapping #EnableAutoConfiguration in two different #Configuration classes enabled by different profiles so that other would exclude security auto-configuration.
What we do (in more sophisticated way) in framework itself is a usage of #Conditional which provides better way to enable/disable parts of auto-configuration.