package teams; import freemarker.template.TemplateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.SessionLocaleResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; import teams.interceptor.FeatureInterceptor; import teams.interceptor.LoginInterceptor; import teams.interceptor.MockLoginInterceptor; import teams.interceptor.VootApiSecurityFilter; import teams.provision.LdapUserDetailsManager; import teams.provision.UserDetailsManager; import teams.repository.PersonRepository; import teams.service.MemberAttributeService; import teams.service.VootClient; import teams.service.impl.VootClientImpl; import teams.service.impl.VootClientMock; import teams.service.mail.MailService; import teams.service.mail.MailServiceImpl; import teams.util.LetterOpener; import teams.util.SpringMvcConfiguration; import javax.sql.DataSource; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; @SpringBootApplication @EnableScheduling @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, FreeMarkerAutoConfiguration.class, TraceWebFilterAutoConfiguration.class, MetricFilterAutoConfiguration.class}) public class Application extends SpringBootServletInitializer { private static final Logger LOG = LoggerFactory.getLogger(Application.class); public static final String DEV_PROFILE_NAME = "dev"; public static final String GROUPZY_PROFILE_NAME = "groupzy"; @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } @Bean @Primary @ConfigurationProperties(prefix = "datasource.teams") public DataSource teamsDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "teamsJdbcTemplate") public JdbcTemplate teamsJdbcTemplate(@Qualifier("teamsDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean public UserDetailsManager userDetailsManager(@Value("${ldap.url}") String url, @Value("${ldap.base}") String base, @Value("${ldap.userDn}") String userDn, @Value("${ldap.password}") String password) { LdapContextSource contextSource = new LdapContextSource(); contextSource.setUrl(url); contextSource.setBase(base); contextSource.setUserDn(userDn); contextSource.setPassword(password); contextSource.afterPropertiesSet(); return new LdapUserDetailsManager(new LdapTemplate(contextSource)); } @Bean public VootClient vootClient(Environment environment, @Value("${voot.accessTokenUri}") String accessTokenUri, @Value("${voot.clientId}") String clientId, @Value("${voot.clientSecret}") String clientSecret, @Value("${voot.scopes}") String scopes, @Value("${voot.serviceUrl}") String serviceUrl) { if (environment.acceptsProfiles(DEV_PROFILE_NAME)) { LOG.debug("Using mock vootclient"); return new VootClientMock(); } return new VootClientImpl(accessTokenUri, clientId, clientSecret, scopes, serviceUrl); } @Bean public LocaleResolver localeResolver() { SessionLocaleResolver localeResolver = new SessionLocaleResolver(); localeResolver.setDefaultLocale(StringUtils.parseLocaleString("EN")); return localeResolver; } @Bean public MailService mailService(Environment environment, JavaMailSender mailSender) { if (environment.acceptsProfiles(DEV_PROFILE_NAME)) { return new LetterOpener(); } else { MailServiceImpl mailService = new MailServiceImpl(); mailService.setMailSender(mailSender); return mailService; } } @Bean public freemarker.template.Configuration freemarkerConfiguration() throws TemplateException, IOException { FreeMarkerConfigurationFactoryBean fmConfigurationFactory = new FreeMarkerConfigurationFactoryBean(); fmConfigurationFactory.setTemplateLoaderPaths("classpath:/mailTemplates/"); freemarker.template.Configuration configuration = fmConfigurationFactory.createConfiguration(); configuration.setIncompatibleImprovements(freemarker.template.Configuration.VERSION_2_3_23); return configuration; } @Autowired @Bean public WebMvcConfigurerAdapter webMvcConfigurerAdapter( Environment environment, PersonRepository personRepository, @Value("${teamsURL}") String teamsURL, @Value("${displayExternalTeams}") Boolean displayExternalTeams, @Value("${displayExternalTeamMembers}") Boolean displayExternalTeamMembers, @Value("${displayAddExternalGroupToTeam}") Boolean displayAddExternalGroupToTeam, @Value("${application.version}") String applicationVersion, @Value("${voot.api.user}") String vootApiUser, @Value("${voot.api.password}") String vootApiPassword, ResourceLoader resourceLoader) throws Exception { List<HandlerInterceptor> interceptors = new ArrayList<>(); String commitId = gitCommitId(resourceLoader, environment); interceptors.add(new FeatureInterceptor(displayExternalTeams, displayExternalTeamMembers, displayAddExternalGroupToTeam, commitId, applicationVersion)); LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("lang"); interceptors.add(localeChangeInterceptor); if (environment.acceptsProfiles(DEV_PROFILE_NAME)) { LOG.debug("Using mock shibboleth"); interceptors.add(new MockLoginInterceptor(teamsURL, personRepository)); } else { interceptors.add(new LoginInterceptor(teamsURL, personRepository)); } interceptors.add(new VootApiSecurityFilter(vootApiUser, vootApiPassword)); return new SpringMvcConfiguration(interceptors); } private String gitCommitId(ResourceLoader resourceLoader, Environment environment) throws IOException { Properties gitProperties = new Properties(); Resource resource = resourceLoader.getResource("classpath:git.properties"); if (!resource.exists() && environment.acceptsProfiles(DEV_PROFILE_NAME)) { return "unknown"; } gitProperties.load(resource.getInputStream()); return gitProperties.getProperty("git.commit.id"); } /** * See https://github.com/spring-projects/spring-boot/issues/2893. This is a JSP limitation as the issue is closed as won't-fix */ @Bean public InternalResourceViewResolver viewResolver(@Value("${spring.mvc.view.prefix:}") String prefix, @Value("${spring.mvc.view.suffix:}") String suffix) { final InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver(); internalResourceViewResolver.setOrder(Ordered.HIGHEST_PRECEDENCE); internalResourceViewResolver.setPrefix(prefix); internalResourceViewResolver.setSuffix(suffix); return internalResourceViewResolver; } }