Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing way to configure spring security?

Is it possible to configure Spring security in a way that it reads configuration details from an external file and configures accordingly ?

(I am not talking about changing config at runtime, I am talking about reading from a file at the time of startup).

An example of my existing Spring security config :

@EnableWebSecurity
@Configuration
public class SecurityConfig {

    @Bean                                                             
    public UserDetailsService userDetailsService() throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("userPass").roles("USER").build());
        manager.createUser(User.withUsername("admin").password("adminPass").roles("ADMIN").build());
        return manager;
    }


    @Configuration
    @Order(1)                                                        
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override       
        public void configure(AuthenticationManagerBuilder auth) 
          throws Exception {            
            auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
            auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        }

        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/v1/**")                               
                .authorizeRequests()
                .antMatchers("/api/v1/**").authenticated()
                    .and()
                .httpBasic();
        }
    }

    @Configuration
    @Order(2)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Override       
        public void configure(AuthenticationManagerBuilder auth) 
          throws Exception {

            auth.inMemoryAuthentication().withUser("user1").password("user").roles("USER");
            auth.inMemoryAuthentication().withUser("admin1").password("admin").roles("ADMIN");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/test/**")
                .authorizeRequests()
                .antMatchers("/api/test/**").authenticated()
                    .and()
                .formLogin();
        }
    }
}

As you can see, I am using multiple configurations (have a look at Order() annotation). What I want to be able to do is decide at the time of startup, the number and types of configuration. For example a first client may want to have 2 configs (e.g.LdapConfig and SamlConfig), a second one may want LdapConfig and SqlConfig and a third one may want 4-5 configs. Is it possible to do that?

NOTE: I am not using Spring Boot

EDIT

Summary of why I want in this way :

By customer I mean the company that will be buying my product. And by users I mean the actual end users of the company that bought my product. So I shipped the product to 3 companies. First will configure it to have ldap auth flow and google-oauth2 auth flow. Users of this first company will be seeing a login page with these 2 options. Company 2 now might have a ldap auth flow and saml auth flow and users of that company will be seeing those 2 options. And the company is selecting the available options before startup.

like image 495
tryingToLearn Avatar asked Feb 15 '18 11:02

tryingToLearn


People also ask

How many ways we can implement Spring Security?

There are basically 2 ways to implement spring security. through bean configuration in . xml files and other by using Annotations.

Which class is used to extended to configure Spring Security?

Java configuration was added to the Spring framework in Spring 3.1 and extended to Spring Security in Spring 3.2 and is defined in a class annotated @Configuration.


1 Answers

You could load properties, e.g. DB credentials, before creating your WebApplicationContext. Look at the following example:

public class WebAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    // Tell the EnvironmentManager to load the properties. The path to the config 
    // file is set by Tomcat's home variable. If you change the container you might 
    // need to change this, too.
    EnvironmentParamManager.initialize(System.getProperty("catalina.home"));

    // now create the Spring Context
    AnnotationConfigWebApplicationContext rootContext = 
        new AnnotationConfigWebApplicationContext();
    rootContext.register(RootConfig.class);
    rootContext.setServletContext(servletContext);
    SpringApplicationContextProvider.configure(rootContext);
    // ... other config
}

The EnvironmentParamManager could look like this. I've decided to make it static so that the properties are accessible from everywhere even in non-Spring parts of the application.

public class EnvironmentParamManager {

  private static Properties properties = new Properties();

  public static void initialize(String pathToConfigFile) {
    BufferedInputStream stream;
    try {
        stream = new BufferedInputStream(new FileInputStream(
           pathToConfigFile + "myconfig.props"));
        properties.load(stream);            
        stream.close();
    } catch (Throwable e) {
        throw new Error("Cannot read environment settings from file " + pathToConfigFile);
    }
  }

  public static String getMongoDBHostname() {
    return properties.getProperty("mongodb.username");
  }

}

When using JavaConfig, you can access your config properties at the Bean creation phase easily like this

@Configuration
public class CoreConfig {

@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
  ...
  ServerAddress address = new 
     ServerAddress(EnvironmentParamManager.getMongoDBHost(), 
                   EnvironmentParamManager.getMongoDBPort());
  ...
}

Of course, you are free to connect to any other services like LDAP etc. in just the same way as you load the local properties file before the Spring Context is bootstrapped. Hope that helps.

like image 192
Jan B. Avatar answered Oct 21 '22 10:10

Jan B.