package org.osiam;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import com.google.common.collect.ImmutableMap;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.MigrationVersion;
import org.osiam.security.authorization.AccessTokenValidationService;
import org.osiam.security.authorization.OsiamMethodSecurityExpressionHandler;
import org.osiam.security.helper.SSLRequestLoggingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.servlet.Filter;
import javax.sql.DataSource;
import java.util.Map;
@SpringBootApplication
@EnableWebMvc
@EnableWebSecurity
@EnableTransactionManagement
@EnableMetrics
@PropertySource("classpath:/resource-server.properties")
public class ResourceServer extends SpringBootServletInitializer {
private static final Map<String, Object> NAMING_STRATEGY = ImmutableMap.<String, Object> of(
"spring.jpa.hibernate.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
@Value("${org.osiam.resource-server.db.driver}")
private String driverClassName;
@Value("${org.osiam.resource-server.db.url}")
private String databaseUrl;
@Value("${org.osiam.resource-server.db.username}")
private String databaseUserName;
@Value("${org.osiam.resource-server.db.password}")
private String databasePassword;
@Value("${org.osiam.resource-server.db.vendor}")
private String databaseVendor;
@Value("${org.osiam.resource-server.db.maximum-pool-size:10}")
private int maximumPoolSize;
@Value("${org.osiam.resource-server.db.connection-timeout-ms:30000}")
private int connectionTimeoutMs;
public static void main(String[] args) {
SpringApplication application = new SpringApplication(ResourceServer.class);
application.setDefaultProperties(NAMING_STRATEGY);
application.run(args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.application().setDefaultProperties(NAMING_STRATEGY);
return application.sources(ResourceServer.class);
}
@Bean
public Filter characterEncodingFilter() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}
@Bean
public Filter sslRequestLoggingFilter() {
return new SSLRequestLoggingFilter();
}
@Primary
@Bean
public DataSource dataSource() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setPoolName("osiam-resource-server-cp");
hikariConfig.setDriverClassName(driverClassName);
hikariConfig.setJdbcUrl(databaseUrl);
hikariConfig.setUsername(databaseUserName);
hikariConfig.setPassword(databasePassword);
hikariConfig.setMaximumPoolSize(maximumPoolSize);
hikariConfig.setConnectionTimeout(connectionTimeoutMs);
return new HikariDataSource(hikariConfig);
}
@Bean(initMethod = "migrate")
public Flyway flyway() {
Flyway flyway = new Flyway();
flyway.setBaselineOnMigrate(true);
flyway.setDataSource(dataSource());
flyway.setLocations("db/migration/" + databaseVendor);
flyway.setTable("resource_server_schema_version");
MigrationVersion version = MigrationVersion.fromVersion("0");
flyway.setBaselineVersion(version);
return flyway;
}
@Bean
public ShaPasswordEncoder passwordEncoder() {
ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder(512);
passwordEncoder.setIterations(1000);
return passwordEncoder;
}
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
private AccessTokenValidationService accessTokenValidationService;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("oauth2res")
.tokenServices(accessTokenValidationService)
.expressionHandler(new OsiamMethodSecurityExpressionHandler());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.accessDeniedHandler(oauthAccessDeniedHandler())
.and()
.authorizeRequests()
.antMatchers("/ServiceProviderConfigs")
.permitAll()
.antMatchers("/me/**")
.access("#osiam.hasScopeForHttpMethod() or #oauth2.hasScope('ADMIN') or #oauth2.hasScope('ME')")
.antMatchers(HttpMethod.POST, "/Users/**")
.access("#osiam.hasScopeForHttpMethod() or #oauth2.hasScope('ADMIN')")
.regexMatchers(HttpMethod.GET, "/Users/?")
.access("#osiam.hasScopeForHttpMethod() or #oauth2.hasScope('ADMIN')")
.antMatchers("/Users/**")
.access("#osiam.hasScopeForHttpMethod() or #oauth2.hasScope('ADMIN') or " +
"#oauth2.hasScope('ME') and #osiam.isOwnerOfResource()")
.anyRequest()
.access("#osiam.hasScopeForHttpMethod() or #oauth2.hasScope('ADMIN')");
}
@Bean
public OAuth2AuthenticationEntryPoint entryPoint() {
OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setRealmName("oauth2-resource-server");
return entryPoint;
}
@Bean
public OAuth2AccessDeniedHandler oauthAccessDeniedHandler() {
return new OAuth2AccessDeniedHandler();
}
}
@Configuration
@EnableMetrics
protected static class MetricsConfiguration extends MetricsConfigurerAdapter {
@Override
public void configureReporters(MetricRegistry metricRegistry) {
metricRegistry.register("jvm.memory", new MemoryUsageGaugeSet());
}
}
}