Skip to content

Instantly share code, notes, and snippets.

@BohdanLevchenko
Created June 30, 2017 10:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BohdanLevchenko/d4f0e57a8330d1b737765438278a2d73 to your computer and use it in GitHub Desktop.
Save BohdanLevchenko/d4f0e57a8330d1b737765438278a2d73 to your computer and use it in GitHub Desktop.
package com.stackoverflow.so44836531;
import java.io.IOException;
import javax.servlet.*;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.UserCredentialsDataSourceAdapter;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
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;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.GenericFilterBean;
/**
* Application properties:
*
* spring.datasource.driver-class-name=org.postgresql.Driver
* spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
* spring.datasource.username=none
* spring.datasource.password=none
*
* Test with: curl -i -u postgres:postgres1 'localhost:8080/home'
*/
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class So44836531Application {
public static void main(String[] args) {
SpringApplication.run(So44836531Application.class, args);
}
@EnableWebSecurity
public static class Security extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false).inMemoryAuthentication().withUser("postgres").password("postgres1").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().mvcMatchers("/").fullyAuthenticated();
}
}
@Bean
public UserCredentialsDataSourceAdapter dataSource(DataSourceProperties properties) {
final UserCredentialsDataSourceAdapter dataSourceAdapter = new UserCredentialsDataSourceAdapter();
dataSourceAdapter.setTargetDataSource(DataSourceBuilder.create()
.driverClassName(properties.getDriverClassName())
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.type(SimpleDriverDataSource.class) // disable pooling
.build());
((SimpleDriverDataSource) dataSourceAdapter.getTargetDataSource()).setDriverClass(org.postgresql.Driver.class); //binder won't set it automatically
return dataSourceAdapter;
}
@Bean
JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Component
public static class DataSourceCredentialsFilter extends GenericFilterBean {
private final UserCredentialsDataSourceAdapter dataSourceAdapter;
@Autowired
public DataSourceCredentialsFilter(UserCredentialsDataSourceAdapter dataSourceAdapter) {
this.dataSourceAdapter = dataSourceAdapter;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
final User user = (User) authentication.getPrincipal();
dataSourceAdapter.setCredentialsForCurrentThread(user.getUsername(), user.getPassword());
chain.doFilter(request, response);
dataSourceAdapter.removeCredentialsFromCurrentThread();
}
}
@Component
public static class AuthenticationHandler {
private final UserCredentialsDataSourceAdapter dataSourceAdapter;
@Autowired
public AuthenticationHandler(UserCredentialsDataSourceAdapter dataSourceAdapter) {
this.dataSourceAdapter = dataSourceAdapter;
}
@EventListener(classes = AuthenticationSuccessEvent.class)
public void authenticationSuccess(AuthenticationSuccessEvent event) {
final Authentication authentication = event.getAuthentication();
final User user = (User) authentication.getPrincipal();
dataSourceAdapter.setCredentialsForCurrentThread(user.getUsername(), user.getPassword()); // <- the most important part
}
}
@RestController
public static class Api {
private final JdbcTemplate jdbcTemplate;
@Autowired
public Api(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
@GetMapping("/home")
public String home() { return jdbcTemplate.queryForObject("select CURRENT_TIMESTAMP", String.class); }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment