Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • arsnova/arsnova-backend
  • pcvl72/arsnova-backend
  • tksl38/arsnova-backend
3 results
Show changes
Showing
with 2242 additions and 514 deletions
package de.thm.arsnova.config;
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.CollectionFactory;
public class PrefixedYamlPropertiesFactoryBean extends YamlPropertiesFactoryBean {
private static final String PREFIX = "arsnova";
@Override
protected Properties createProperties() {
final Properties result = CollectionFactory.createStringAdaptingProperties();
process((properties, map) -> properties.forEach((k, v) -> {
if (k.toString().startsWith(PREFIX + ".")) {
result.put(k.toString().substring(PREFIX.length() + 1), v);
}
}));
return result;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,31 +15,46 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.scribe.up.provider.impl.FacebookProvider;
import org.scribe.up.provider.impl.Google2Provider;
import org.scribe.up.provider.impl.Google2Provider.Google2Scope;
import org.scribe.up.provider.impl.TwitterProvider;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.pac4j.core.client.Client;
import org.pac4j.core.config.Config;
import org.pac4j.core.http.callback.PathParameterCallbackUrlResolver;
import org.pac4j.oauth.client.FacebookClient;
import org.pac4j.oauth.client.TwitterClient;
import org.pac4j.oidc.client.GoogleOidcClient;
import org.pac4j.oidc.client.OidcClient;
import org.pac4j.oidc.config.OidcConfiguration;
import org.pac4j.saml.client.SAML2Client;
import org.pac4j.saml.config.SAML2Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.slf4j.event.Level;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
......@@ -47,152 +62,299 @@ import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
import org.springframework.security.crypto.keygen.StringKeyGenerator;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.ldap.authentication.NullLdapAuthoritiesPopulator;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.ServletContextAware;
import com.github.leleuj.ss.oauth.client.authentication.OAuthAuthenticationProvider;
import com.github.leleuj.ss.oauth.client.web.OAuthAuthenticationEntryPoint;
import com.github.leleuj.ss.oauth.client.web.OAuthAuthenticationFilter;
import de.thm.arsnova.CASLogoutSuccessHandler;
import de.thm.arsnova.CasUserDetailsService;
import de.thm.arsnova.LoginAuthenticationFailureHandler;
import de.thm.arsnova.LoginAuthenticationSucessHandler;
import de.thm.arsnova.security.ApplicationPermissionEvaluator;
import de.thm.arsnova.security.DbUserDetailsService;
import de.thm.arsnova.config.properties.AuthenticationProviderProperties;
import de.thm.arsnova.config.properties.SecurityProperties;
import de.thm.arsnova.config.properties.SystemProperties;
import de.thm.arsnova.controller.ControllerExceptionHelper;
import de.thm.arsnova.security.CasLogoutSuccessHandler;
import de.thm.arsnova.security.CasUserDetailsService;
import de.thm.arsnova.security.CustomLdapUserDetailsMapper;
import de.thm.arsnova.security.LoginAuthenticationFailureHandler;
import de.thm.arsnova.security.LoginAuthenticationSucessHandler;
import de.thm.arsnova.security.RegisteredUserDetailsService;
import de.thm.arsnova.security.jwt.JwtAuthenticationProvider;
import de.thm.arsnova.security.jwt.JwtTokenFilter;
import de.thm.arsnova.security.pac4j.SsoAuthenticationProvider;
import de.thm.arsnova.security.pac4j.SsoCallbackFilter;
/**
* Loads property file and configures components used for authentication.
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableConfigurationProperties({
AuthenticationProviderProperties.class,
SecurityProperties.class})
@Profile("!test")
public class SecurityConfig extends WebSecurityConfigurerAdapter implements ServletContextAware {
private final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
public class SecurityConfig extends WebSecurityConfigurerAdapter {
public static final String AUTH_CALLBACK_PATH = "/auth/callback";
public static final String OAUTH_CALLBACK_PATH = AUTH_CALLBACK_PATH + "/oauth";
public static final String SAML_CALLBACK_PATH = AUTH_CALLBACK_PATH + "/saml";
public static final String CAS_CALLBACK_PATH = AUTH_CALLBACK_PATH + "/cas";
public static final String CAS_LOGOUT_PATH = "/auth/logout/cas";
public static final String RUN_AS_KEY_PREFIX = "RUN_AS_KEY";
public static final String INTERNAL_PROVIDER_ID = "user-db";
public static final String LDAP_PROVIDER_ID = "ldap";
public static final String OIDC_PROVIDER_ID = "oidc";
public static final String SAML_PROVIDER_ID = "saml";
public static final String CAS_PROVIDER_ID = "cas";
public static final String GOOGLE_PROVIDER_ID = "google";
public static final String TWITTER_PROVIDER_ID = "twitter";
public static final String FACEBOOK_PROVIDER_ID = "facebook";
private static final String OIDC_DISCOVERY_PATH = "/.well-known/openid-configuration";
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
private ServletContext servletContext;
private AuthenticationProviderProperties providerProperties;
private String rootUrl;
private String apiPath;
public SecurityConfig(
final SystemProperties systemProperties,
final AuthenticationProviderProperties authenticationProviderProperties,
final ServletContext servletContext) {
this.providerProperties = authenticationProviderProperties;
this.rootUrl = systemProperties.getRootUrl();
this.apiPath = systemProperties.getApi().getProxyPath();
this.servletContext = servletContext;
}
@Value("${root-url}") private String rootUrl;
@Value("${security.user-db.enabled}") private boolean dbAuthEnabled;
@PostConstruct
private void init() {
if (apiPath == null || "".equals(apiPath)) {
apiPath = servletContext.getContextPath();
}
}
@Value("${security.ldap.enabled}") private boolean ldapEnabled;
@Value("${security.ldap.url}") private String ldapUrl;
@Value("${security.ldap.user-dn-pattern}") private String ldapUserDn;
public class HttpSecurityConfig extends WebSecurityConfigurerAdapter {
protected AuthenticationEntryPoint authenticationEntryPoint;
protected AccessDeniedHandler accessDeniedHandler;
@Value("${security.cas.enabled}") private boolean casEnabled;
@Value("${security.cas-server-url}") private String casUrl;
public HttpSecurityConfig(final AuthenticationEntryPoint authenticationEntryPoint,
final AccessDeniedHandler accessDeniedHandler) {
this.authenticationEntryPoint = authenticationEntryPoint;
this.accessDeniedHandler = accessDeniedHandler;
}
@Value("${security.facebook.enabled}") private boolean facebookEnabled;
@Value("${security.facebook.key}") private String facebookKey;
@Value("${security.facebook.secret}") private String facebookSecret;
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
http.csrf().disable();
http.headers().addHeaderWriter(new HstsHeaderWriter(false));
http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
if (providerProperties.getCas().isEnabled()) {
http.addFilter(casAuthenticationFilter());
http.addFilter(casLogoutFilter());
}
if (providerProperties.getSaml().isEnabled()) {
http.addFilterAfter(samlCallbackFilter(), UsernamePasswordAuthenticationFilter.class);
}
if (providerProperties.getOidc().stream().anyMatch(p -> p.isEnabled())
|| providerProperties.getOauth().values().stream().anyMatch(p -> p.isEnabled())) {
http.addFilterAfter(oauthCallbackFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
}
@Value("${security.twitter.enabled}") private boolean twitterEnabled;
@Value("${security.twitter.key}") private String twitterKey;
@Value("${security.twitter.secret}") private String twitterSecret;
@Configuration
@Order(2)
@Profile("!test")
public class StatelessHttpSecurityConfig extends HttpSecurityConfig {
public StatelessHttpSecurityConfig(
@Qualifier("restAuthenticationEntryPoint") final AuthenticationEntryPoint authenticationEntryPoint,
final AccessDeniedHandler accessDeniedHandler) {
super(authenticationEntryPoint, accessDeniedHandler);
}
@Value("${security.google.enabled}") private boolean googleEnabled;
@Value("${security.google.key}") private String googleKey;
@Value("${security.google.secret}") private String googleSecret;
@Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.antMatcher("/**");
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint());
http.csrf().disable();
@Configuration
@Order(1)
@Profile("!test")
public class StatefulHttpSecurityConfig extends HttpSecurityConfig {
public StatefulHttpSecurityConfig(
@Qualifier("restAuthenticationEntryPoint") final AuthenticationEntryPoint authenticationEntryPoint,
final AccessDeniedHandler accessDeniedHandler) {
super(authenticationEntryPoint, accessDeniedHandler);
}
if (casEnabled) {
http.addFilter(casAuthenticationFilter());
http.addFilter(casLogoutFilter());
@Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.requestMatchers().antMatchers(AUTH_CALLBACK_PATH + "/**", "/v2/**");
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}
if (googleEnabled) {
http.addFilterAfter(googleFilter(), CasAuthenticationFilter.class);
}
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@Profile("!test")
public class ManagementHttpSecurityConfig extends HttpSecurityConfig {
private final String managementPath;
public ManagementHttpSecurityConfig(
@Qualifier("restAuthenticationEntryPoint") final AuthenticationEntryPoint authenticationEntryPoint,
final AccessDeniedHandler accessDeniedHandler,
final WebEndpointProperties webEndpointProperties) {
super(authenticationEntryPoint, accessDeniedHandler);
this.managementPath = webEndpointProperties.getBasePath();
}
if (facebookEnabled) {
http.addFilterAfter(facebookFilter(), CasAuthenticationFilter.class);
@Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.antMatcher(managementPath + "/**");
http.authorizeRequests()
.antMatchers(managementPath + "/health", managementPath + "/info").permitAll()
.antMatchers(
managementPath + "/health/**",
managementPath + "/metrics",
managementPath + "/metrics/**",
managementPath + "/prometheus",
managementPath + "/stats"
).hasAnyRole("ADMIN", "MONITORING")
.anyRequest().hasRole("ADMIN");
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
if (twitterEnabled) {
http.addFilterAfter(twitterFilter(), CasAuthenticationFilter.class);
}
@Configuration
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected RunAsManager runAsManager() {
final StringKeyGenerator keyGenerator = new Base64StringKeyGenerator();
final RunAsManagerImpl runAsManager = new RunAsManagerImpl();
/* Since RunAsTokens should currently only be used internally, we generate a random key. */
runAsManager.setKey(RUN_AS_KEY_PREFIX + keyGenerator.generateKey());
return runAsManager;
}
};
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
List<String> providers = new ArrayList<>();
if (dbAuthEnabled) {
providers.add("user-db");
auth.authenticationProvider(daoAuthenticationProvider());
}
if (ldapEnabled) {
providers.add("ldap");
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
final List<String> providers = new ArrayList<>();
auth.authenticationProvider(jwtAuthenticationProvider());
logger.info("oauthProps: {}", providerProperties.getOauth());
if (providerProperties.getLdap().stream().anyMatch(p -> p.isEnabled())) {
providers.add(LDAP_PROVIDER_ID);
auth.authenticationProvider(ldapAuthenticationProvider());
}
if (casEnabled) {
providers.add("cas");
if (providerProperties.getCas().isEnabled()) {
providers.add(CAS_PROVIDER_ID);
auth.authenticationProvider(casAuthenticationProvider());
}
if (googleEnabled) {
providers.add("google");
auth.authenticationProvider(googleAuthProvider());
if (providerProperties.getRegistered().isEnabled()) {
providers.add(INTERNAL_PROVIDER_ID);
auth.authenticationProvider(daoAuthenticationProvider());
}
if (providerProperties.getSaml().isEnabled()) {
providers.add(SAML_PROVIDER_ID);
}
if (facebookEnabled) {
providers.add("facebook");
auth.authenticationProvider(facebookAuthProvider());
boolean oauthOrOidcProvider = false;
if (providerProperties.getOidc().stream().anyMatch(p -> p.isEnabled())) {
oauthOrOidcProvider = true;
providers.add(OIDC_PROVIDER_ID);
}
if (twitterEnabled) {
providers.add("twitter");
auth.authenticationProvider(twitterAuthProvider());
if (providerProperties.getOauth().values().stream().anyMatch(p -> p.isEnabled())) {
oauthOrOidcProvider = true;
if (providerProperties.getOauth().containsKey(GOOGLE_PROVIDER_ID)
&& providerProperties.getOauth().get(GOOGLE_PROVIDER_ID).isEnabled()) {
providers.add(GOOGLE_PROVIDER_ID);
}
if (providerProperties.getOauth().containsKey(FACEBOOK_PROVIDER_ID)
&& providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID).isEnabled()) {
providers.add(FACEBOOK_PROVIDER_ID);
}
if (providerProperties.getOauth().containsKey(TWITTER_PROVIDER_ID)
&& providerProperties.getOauth().get(TWITTER_PROVIDER_ID).isEnabled()) {
providers.add(TWITTER_PROVIDER_ID);
}
}
if (oauthOrOidcProvider) {
auth.authenticationProvider(ssoAuthenticationProvider());
}
logger.info("Enabled authentication providers: {}", providers);
};
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManager();
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocations(new Resource[] {
new ClassPathResource("arsnova.properties.example"),
new FileSystemResource("file:///etc/arsnova/arsnova.properties"),
});
configurer.setIgnoreResourceNotFound(true);
configurer.setIgnoreUnresolvablePlaceholders(false);
return configurer;
public static AuthenticationEntryPoint restAuthenticationEntryPoint(
@Qualifier("defaultJsonMessageConverter")
final MappingJackson2HttpMessageConverter jackson2HttpMessageConverter,
final ControllerExceptionHelper controllerExceptionHelper) {
return (request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
response.getWriter().write(jackson2HttpMessageConverter.getObjectMapper().writeValueAsString(
controllerExceptionHelper.handleException(accessDeniedException, Level.DEBUG)));
};
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
public AccessDeniedHandler customAccessDeniedHandler(
@Qualifier("defaultJsonMessageConverter")
final MappingJackson2HttpMessageConverter jackson2HttpMessageConverter,
final ControllerExceptionHelper controllerExceptionHelper) {
return (request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
response.getWriter().write(jackson2HttpMessageConverter.getObjectMapper().writeValueAsString(
controllerExceptionHelper.handleException(accessDeniedException, Level.DEBUG)));
};
}
@Bean
public PermissionEvaluator permissionEvaluator() {
return new ApplicationPermissionEvaluator();
public JwtAuthenticationProvider jwtAuthenticationProvider() {
return new JwtAuthenticationProvider();
}
@Bean
public static AuthenticationEntryPoint restAuthenticationEntryPoint() {
return new Http403ForbiddenEntryPoint();
public JwtTokenFilter jwtTokenFilter() throws Exception {
final JwtTokenFilter jwtTokenFilter = new JwtTokenFilter();
return jwtTokenFilter;
}
@Bean
......@@ -216,7 +378,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter implements Serv
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(dbUserDetailsService());
authProvider.setUserDetailsService(registeredUserDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
......@@ -228,8 +390,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter implements Serv
}
@Bean
public DbUserDetailsService dbUserDetailsService() {
return new DbUserDetailsService();
public RegisteredUserDetailsService registeredUserDetailsService() {
return new RegisteredUserDetailsService();
}
@Bean
......@@ -240,38 +402,99 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter implements Serv
// LDAP Authentication Configuration
@Bean
public LdapAuthenticationProvider ldapAuthenticationProvider() throws Exception {
return new LdapAuthenticationProvider(ldapAuthenticator(), ldapAuthoritiesPopulator());
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapAuthenticationProvider ldapAuthenticationProvider() {
final LdapAuthenticationProvider ldapAuthenticationProvider =
new LdapAuthenticationProvider(ldapAuthenticator(), ldapAuthoritiesPopulator());
ldapAuthenticationProvider.setUserDetailsContextMapper(customLdapUserDetailsMapper());
return ldapAuthenticationProvider;
}
@Bean
public LdapContextSource ldapContextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapUrl);
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapContextSource ldapContextSource() {
final AuthenticationProviderProperties.Ldap ldapProperties = providerProperties.getLdap().get(0);
final DefaultSpringSecurityContextSource contextSource =
new DefaultSpringSecurityContextSource(ldapProperties.getHostUrl());
contextSource.setBaseEnvironmentProperties(Collections.singletonMap(
"com.sun.jndi.ldap.connect.timeout", String.valueOf(ldapProperties.getConnectTimeout())));
/* TODO: implement support for LDAP bind using manager credentials */
// contextSource.setUserDn(ldapManagerUserDn);
// contextSource.setPassword(ldapManagerPassword);
if (!"".equals(ldapProperties.getManagerUserDn()) && !"".equals(ldapProperties.getManagerPassword())) {
logger.debug("ldapManagerUserDn: {}", ldapProperties.getManagerUserDn());
contextSource.setUserDn(ldapProperties.getManagerUserDn());
contextSource.setPassword(ldapProperties.getManagerPassword());
}
return contextSource;
}
@Bean
public LdapAuthenticator ldapAuthenticator() throws Exception {
BindAuthenticator authenticator = new BindAuthenticator(ldapContextSource());
authenticator.setUserDnPatterns(new String[] {ldapUserDn});
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapAuthenticator ldapAuthenticator() {
final AuthenticationProviderProperties.Ldap ldapProperties = providerProperties.getLdap().get(0);
final BindAuthenticator authenticator = new BindAuthenticator(ldapContextSource());
authenticator.setUserAttributes(new String[] {ldapProperties.getUserIdAttribute()});
if (!"".equals(ldapProperties.getUserSearchFilter())) {
logger.debug("ldapSearch: {} {}", ldapProperties.getUserSearchBase(), ldapProperties.getUserSearchFilter());
authenticator.setUserSearch(new FilterBasedLdapUserSearch(
ldapProperties.getUserSearchBase(), ldapProperties.getUserSearchFilter(), ldapContextSource()));
} else {
logger.debug("ldapUserDn: {}", ldapProperties.getUserDnPattern());
authenticator.setUserDnPatterns(new String[] {ldapProperties.getUserDnPattern()});
}
return authenticator;
}
@Bean
public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() throws Exception {
return new DefaultLdapAuthoritiesPopulator(ldapContextSource(), null);
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
return new NullLdapAuthoritiesPopulator();
}
@Bean
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapUserDetailsMapper customLdapUserDetailsMapper() {
final AuthenticationProviderProperties.Ldap ldapProperties = providerProperties.getLdap().get(0);
logger.debug("ldapUserIdAttr: {}", ldapProperties.getUserIdAttribute());
return new CustomLdapUserDetailsMapper(ldapProperties.getUserIdAttribute());
}
@Bean
@ConditionalOnProperty(
name = "ldap[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LdapTemplate ldapTemplate() {
return new LdapTemplate(ldapContextSource());
}
// CAS Authentication Configuration
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider authProvider = new CasAuthenticationProvider();
final CasAuthenticationProvider authProvider = new CasAuthenticationProvider();
authProvider.setAuthenticationUserDetailsService(casUserDetailsService());
authProvider.setServiceProperties(casServiceProperties());
authProvider.setTicketValidator(casTicketValidator());
......@@ -281,37 +504,59 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter implements Serv
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public CasUserDetailsService casUserDetailsService() {
return new CasUserDetailsService();
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public ServiceProperties casServiceProperties() {
ServiceProperties properties = new ServiceProperties();
properties.setService(rootUrl + servletContext.getContextPath() + "/j_spring_cas_security_check");
final ServiceProperties properties = new ServiceProperties();
properties.setService(rootUrl + apiPath + CAS_CALLBACK_PATH);
properties.setSendRenew(false);
return properties;
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public Cas20ProxyTicketValidator casTicketValidator() {
return new Cas20ProxyTicketValidator(casUrl);
return new Cas20ProxyTicketValidator(providerProperties.getCas().getHostUrl());
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
entryPoint.setLoginUrl(casUrl + "/login");
final CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
entryPoint.setLoginUrl(providerProperties.getCas().getHostUrl() + "/login");
entryPoint.setServiceProperties(casServiceProperties());
return entryPoint;
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
final CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setServiceProperties(casServiceProperties());
filter.setFilterProcessesUrl("/**" + CAS_CALLBACK_PATH);
filter.setAuthenticationSuccessHandler(successHandler());
filter.setAuthenticationFailureHandler(failureHandler());
......@@ -319,125 +564,203 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter implements Serv
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LogoutFilter casLogoutFilter() {
LogoutFilter filter = new LogoutFilter(casLogoutSuccessHandler(), logoutHandler());
filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/j_spring_cas_security_logout"));
final LogoutFilter filter = new LogoutFilter(casLogoutSuccessHandler(), logoutHandler());
filter.setLogoutRequestMatcher(new AntPathRequestMatcher("/**" + CAS_LOGOUT_PATH));
return filter;
}
@Bean
@ConditionalOnProperty(
name = "cas.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public LogoutSuccessHandler casLogoutSuccessHandler() {
CASLogoutSuccessHandler handler = new CASLogoutSuccessHandler();
handler.setCasUrl(casUrl);
final CasLogoutSuccessHandler handler = new CasLogoutSuccessHandler();
handler.setCasUrl(providerProperties.getCas().getHostUrl());
handler.setDefaultTarget(rootUrl);
return handler;
}
// Facebook Authentication Configuration
// SAML Authentication Configuration
@Bean
public OAuthAuthenticationEntryPoint facebookEntryPoint() {
final OAuthAuthenticationEntryPoint entryPoint = new OAuthAuthenticationEntryPoint();
entryPoint.setProvider(facebookProvider());
return entryPoint;
@ConditionalOnProperty(
name = "saml.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public Config samlConfig() {
return new Config(rootUrl + apiPath + SAML_CALLBACK_PATH, saml2Client());
}
@Bean
public FacebookProvider facebookProvider() {
final FacebookProvider provider = new FacebookProvider();
provider.setKey(facebookKey);
provider.setSecret(facebookSecret);
provider.setCallbackUrl(rootUrl + servletContext.getContextPath() + "/j_spring_facebook_security_check");
@ConditionalOnProperty(
name = "saml.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public SsoCallbackFilter samlCallbackFilter() throws Exception {
final SsoCallbackFilter callbackFilter = new SsoCallbackFilter(samlConfig(), SAML_CALLBACK_PATH);
callbackFilter.setAuthenticationManager(authenticationManager());
callbackFilter.setAuthenticationSuccessHandler(successHandler());
callbackFilter.setAuthenticationFailureHandler(failureHandler());
return provider;
return callbackFilter;
}
@Bean
public OAuthAuthenticationFilter facebookFilter() throws Exception {
final OAuthAuthenticationFilter filter = new OAuthAuthenticationFilter("/j_spring_facebook_security_check");
filter.setProvider(facebookProvider());
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationFailureHandler(failureHandler());
filter.setAuthenticationSuccessHandler(successHandler());
@ConditionalOnProperty(
name = "saml.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public SAML2Client saml2Client() {
final AuthenticationProviderProperties.Saml samlProperties = providerProperties.getSaml();
final SAML2Configuration config = new SAML2Configuration(
"file:" + samlProperties.getKeystore().getFile(),
samlProperties.getKeystore().getStorePassword(),
samlProperties.getKeystore().getKeyPassword(),
"file:" + samlProperties.getIdp().getMetaFile());
config.setKeystoreAlias(samlProperties.getKeystore().getKeyAlias());
if (!samlProperties.getSp().getMetaFile().isEmpty()) {
config.setServiceProviderMetadataPath("file:" + samlProperties.getSp().getMetaFile());
}
if (!samlProperties.getSp().getEntityId().isEmpty()) {
config.setServiceProviderEntityId(samlProperties.getSp().getEntityId());
}
config.setAssertionConsumerServiceIndex(samlProperties.getAssertionConsumerServiceIndex());
config.setMaximumAuthenticationLifetime(samlProperties.getMaxAuthenticationLifetime());
config.setAuthnRequestBindingType(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
config.setAuthnRequestSigned(true);
config.setWantsAssertionsSigned(true);
final SAML2Client client = new SAML2Client(config);
client.setName(SAML_PROVIDER_ID);
client.setCallbackUrl(rootUrl + apiPath + AUTH_CALLBACK_PATH);
client.setCallbackUrlResolver(pathParameterCallbackUrlResolver());
return filter;
/* Initialize the client manually for the metadata endpoint */
client.init();
return client;
}
// OAuth Authentication Configuration
@Bean
public OAuthAuthenticationProvider facebookAuthProvider() {
final OAuthAuthenticationProvider authProvider = new OAuthAuthenticationProvider();
authProvider.setProvider(facebookProvider());
public Config oauthConfig() {
final List<Client> clients = new ArrayList<>();
if (providerProperties.getOidc().stream().anyMatch(p -> p.isEnabled())) {
clients.add(oidcClient());
}
if (providerProperties.getOauth().containsKey(FACEBOOK_PROVIDER_ID)
&& providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID).isEnabled()) {
clients.add(facebookClient());
}
if (providerProperties.getOauth().containsKey(GOOGLE_PROVIDER_ID)
&& providerProperties.getOauth().get(GOOGLE_PROVIDER_ID).isEnabled()) {
clients.add(googleClient());
}
if (providerProperties.getOauth().containsKey(TWITTER_PROVIDER_ID)
&& providerProperties.getOauth().get(TWITTER_PROVIDER_ID).isEnabled()) {
clients.add(twitterClient());
}
return authProvider;
return new Config(rootUrl + apiPath + OAUTH_CALLBACK_PATH, clients);
}
// Twitter Authentication Configuration
@Bean
public TwitterProvider twitterProvider() {
final TwitterProvider provider = new TwitterProvider();
provider.setKey(twitterKey);
provider.setSecret(twitterSecret);
provider.setCallbackUrl(rootUrl + servletContext.getContextPath() + "/j_spring_twitter_security_check");
public SsoCallbackFilter oauthCallbackFilter() throws Exception {
final SsoCallbackFilter callbackFilter = new SsoCallbackFilter(oauthConfig(), OAUTH_CALLBACK_PATH + "/**");
callbackFilter.setAuthenticationManager(authenticationManager());
callbackFilter.setAuthenticationSuccessHandler(successHandler());
callbackFilter.setAuthenticationFailureHandler(failureHandler());
return provider;
return callbackFilter;
}
@Bean
public OAuthAuthenticationFilter twitterFilter() throws Exception {
final OAuthAuthenticationFilter filter = new OAuthAuthenticationFilter("/j_spring_twitter_security_check");
filter.setProvider(twitterProvider());
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationFailureHandler(failureHandler());
filter.setAuthenticationSuccessHandler(successHandler());
return filter;
public SsoAuthenticationProvider ssoAuthenticationProvider() {
return new SsoAuthenticationProvider();
}
@Bean
public OAuthAuthenticationProvider twitterAuthProvider() {
final OAuthAuthenticationProvider authProvider = new OAuthAuthenticationProvider();
authProvider.setProvider(twitterProvider());
return authProvider;
public PathParameterCallbackUrlResolver pathParameterCallbackUrlResolver() {
return new PathParameterCallbackUrlResolver();
}
// Google Authentication Configuration
@Bean
public Google2Provider googleProvider() {
final Google2Provider provider = new Google2Provider();
provider.setKey(googleKey);
provider.setSecret(googleSecret);
provider.setCallbackUrl(rootUrl + servletContext.getContextPath() + "/j_spring_google_security_check");
provider.setScope(Google2Scope.EMAIL);
@ConditionalOnProperty(
name = "oidc[0].enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public OidcClient oidcClient() {
final AuthenticationProviderProperties.Oidc oidcProperties = providerProperties.getOidc().get(0);
final OidcConfiguration config = new OidcConfiguration();
config.setDiscoveryURI(oidcProperties.getIssuer() + OIDC_DISCOVERY_PATH);
config.setClientId(oidcProperties.getClientId());
config.setSecret(oidcProperties.getSecret());
config.setScope("openid");
final OidcClient client = new OidcClient(config);
client.setName(OIDC_PROVIDER_ID);
client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH);
client.setCallbackUrlResolver(pathParameterCallbackUrlResolver());
return provider;
return client;
}
@Bean
public OAuthAuthenticationFilter googleFilter() throws Exception {
final OAuthAuthenticationFilter filter = new OAuthAuthenticationFilter("/j_spring_google_security_check");
filter.setProvider(googleProvider());
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationFailureHandler(failureHandler());
filter.setAuthenticationSuccessHandler(successHandler());
@ConditionalOnProperty(
name = "oauth.facebook.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public FacebookClient facebookClient() {
final AuthenticationProviderProperties.Oauth oauthProperties =
providerProperties.getOauth().get(FACEBOOK_PROVIDER_ID);
final FacebookClient client = new FacebookClient(oauthProperties.getKey(), oauthProperties.getSecret());
client.setName(FACEBOOK_PROVIDER_ID);
client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH);
client.setCallbackUrlResolver(pathParameterCallbackUrlResolver());
return filter;
return client;
}
@Bean
public OAuthAuthenticationProvider googleAuthProvider() {
final OAuthAuthenticationProvider authProvider = new OAuthAuthenticationProvider();
authProvider.setProvider(googleProvider());
@ConditionalOnProperty(
name = "oauth.twitter.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public TwitterClient twitterClient() {
final AuthenticationProviderProperties.Oauth oauthProperties =
providerProperties.getOauth().get(TWITTER_PROVIDER_ID);
final TwitterClient client = new TwitterClient(oauthProperties.getKey(), oauthProperties.getSecret());
client.setName(TWITTER_PROVIDER_ID);
client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH);
client.setCallbackUrlResolver(pathParameterCallbackUrlResolver());
return authProvider;
return client;
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
@Bean
@ConditionalOnProperty(
name = "oauth.google.enabled",
prefix = AuthenticationProviderProperties.PREFIX,
havingValue = "true")
public GoogleOidcClient googleClient() {
final AuthenticationProviderProperties.Oauth oauthProperties =
providerProperties.getOauth().get(GOOGLE_PROVIDER_ID);
final OidcConfiguration config = new OidcConfiguration();
config.setClientId(oauthProperties.getKey());
config.setSecret(oauthProperties.getSecret());
config.setScope("openid email");
final GoogleOidcClient client = new GoogleOidcClient(config);
client.setName(GOOGLE_PROVIDER_ID);
client.setCallbackUrl(rootUrl + apiPath + OAUTH_CALLBACK_PATH);
client.setCallbackUrlResolver(pathParameterCallbackUrlResolver());
return client;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
package de.thm.arsnova.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import de.thm.arsnova.config.properties.MessageBrokerProperties;
import de.thm.arsnova.config.properties.SecurityProperties;
import de.thm.arsnova.websocket.handler.AuthChannelInterceptorAdapter;
@Configuration
@EnableWebSocketMessageBroker
@EnableConfigurationProperties(MessageBrokerProperties.class)
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private static final String MESSAGING_PREFIX = "/backend";
private static final String[] DESTINATION_PREFIX = {"/exchange", "/topic", "/queue"};
private static final String USER_REGISTRY_BROADCAST = "/topic/log-user-registry";
private static final String USER_DESTINATION_BROADCAST = "/queue/log-unresolved-user";
private final MessageBrokerProperties.Relay relayProperties;
private final AuthChannelInterceptorAdapter authChannelInterceptorAdapter;
private String[] corsOrigins;
@Autowired
public WebSocketConfig(
final MessageBrokerProperties messageBrokerProperties,
final SecurityProperties securityProperties,
final AuthChannelInterceptorAdapter authChannelInterceptorAdapter) {
this.relayProperties = messageBrokerProperties.getRelay();
this.corsOrigins = securityProperties.getCorsOrigins().stream().toArray(String[]::new);
this.authChannelInterceptorAdapter = authChannelInterceptorAdapter;
}
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes(MESSAGING_PREFIX);
if (relayProperties.isEnabled()) {
config
.enableStompBrokerRelay(DESTINATION_PREFIX)
.setUserRegistryBroadcast(USER_REGISTRY_BROADCAST)
.setUserDestinationBroadcast(USER_DESTINATION_BROADCAST)
.setRelayHost(relayProperties.getHost())
.setRelayPort(relayProperties.getPort())
.setClientLogin(relayProperties.getUsername())
.setClientPasscode(relayProperties.getPassword());
} else {
config.enableSimpleBroker(DESTINATION_PREFIX);
}
}
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins(corsOrigins).withSockJS();
}
@Override
public void configureClientInboundChannel(final ChannelRegistration registration) {
registration.interceptors(authChannelInterceptorAdapter);
}
}
package de.thm.arsnova.config;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(final String name, final EncodedResource resource)
throws IOException {
try {
final YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new PrefixedYamlPropertiesFactoryBean();
yamlPropertiesFactoryBean.setResources(resource.getResource());
yamlPropertiesFactoryBean.afterPropertiesSet();
final Properties properties = yamlPropertiesFactoryBean.getObject();
return new PropertiesPropertySource(name != null ? name : resource.getResource().getFilename(), properties);
} catch (final IllegalStateException e) {
if (e.getCause() instanceof FileNotFoundException) {
throw (FileNotFoundException) e.getCause();
}
throw e;
}
}
}
/**
* Configuration of Spring's and ARSnova's components.
*/
package de.thm.arsnova.config;
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.style.ToStringCreator;
@ConfigurationProperties(AuthenticationProviderProperties.PREFIX)
public class AuthenticationProviderProperties {
public static final String PREFIX = SecurityProperties.PREFIX + ".authentication-providers";
public abstract static class Provider {
public enum Role {
MODERATOR,
PARTICIPANT
}
private boolean enabled;
private String title;
private int order;
private Set<Role> allowedRoles;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public String getTitle() {
return title;
}
public void setTitle(final String title) {
this.title = title;
}
public int getOrder() {
return order;
}
public void setOrder(final int order) {
this.order = order;
}
public Set<Role> getAllowedRoles() {
return allowedRoles;
}
public void setAllowedRoles(final Set<Role> allowedRoles) {
this.allowedRoles = allowedRoles;
}
}
public static class Registered extends Provider {
private List<String> allowedEmailDomains;
private String registrationMailSubject;
private String registrationMailBody;
private String resetPasswordMailSubject;
private String resetPasswordMailBody;
public List<String> getAllowedEmailDomains() {
return allowedEmailDomains;
}
public void setAllowedEmailDomains(final List<String> allowedEmailDomains) {
this.allowedEmailDomains = allowedEmailDomains;
}
public String getRegistrationMailSubject() {
return registrationMailSubject;
}
public void setRegistrationMailSubject(final String registrationMailSubject) {
this.registrationMailSubject = registrationMailSubject;
}
public String getRegistrationMailBody() {
return registrationMailBody;
}
public void setRegistrationMailBody(final String registrationMailBody) {
this.registrationMailBody = registrationMailBody;
}
public String getResetPasswordMailSubject() {
return resetPasswordMailSubject;
}
public void setResetPasswordMailSubject(final String resetPasswordMailSubject) {
this.resetPasswordMailSubject = resetPasswordMailSubject;
}
public String getResetPasswordMailBody() {
return resetPasswordMailBody;
}
public void setResetPasswordMailBody(final String resetPasswordMailBody) {
this.resetPasswordMailBody = resetPasswordMailBody;
}
}
public static class Guest extends Provider {
}
public static class Ldap extends Provider {
private String hostUrl;
private String userDnPattern;
private String userIdAttribute;
private String userSearchFilter;
private String userSearchBase;
private String managerUserDn;
private String managerPassword;
private int connectTimeout;
public String getHostUrl() {
return hostUrl;
}
public void setHostUrl(final String hostUrl) {
this.hostUrl = hostUrl;
}
public String getUserDnPattern() {
return userDnPattern;
}
public void setUserDnPattern(final String userDnPattern) {
this.userDnPattern = userDnPattern;
}
public String getUserIdAttribute() {
return userIdAttribute;
}
public void setUserIdAttribute(final String userIdAttribute) {
this.userIdAttribute = userIdAttribute;
}
public String getUserSearchFilter() {
return userSearchFilter;
}
public void setUserSearchFilter(final String userSearchFilter) {
this.userSearchFilter = userSearchFilter;
}
public String getUserSearchBase() {
return userSearchBase;
}
public void setUserSearchBase(final String userSearchBase) {
this.userSearchBase = userSearchBase;
}
public String getManagerUserDn() {
return managerUserDn;
}
public void setManagerUserDn(final String managerUserDn) {
this.managerUserDn = managerUserDn;
}
public String getManagerPassword() {
return managerPassword;
}
public void setManagerPassword(final String managerPassword) {
this.managerPassword = managerPassword;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(final int connectTimeout) {
this.connectTimeout = connectTimeout;
}
}
public static class Oidc extends Provider {
private String issuer;
private String clientId;
private String secret;
public String getIssuer() {
return issuer;
}
public void setIssuer(final String issuer) {
this.issuer = issuer;
}
public String getClientId() {
return clientId;
}
public void setClientId(final String clientId) {
this.clientId = clientId;
}
public String getSecret() {
return secret;
}
public void setSecret(final String secret) {
this.secret = secret;
}
}
public static class Saml extends Provider {
public static class Idp {
private String metaFile;
public String getMetaFile() {
return metaFile;
}
public void setMetaFile(final String metaFile) {
this.metaFile = metaFile;
}
}
public static class Sp {
private String metaFile;
private String entityId;
public String getMetaFile() {
return metaFile;
}
public void setMetaFile(final String metaFile) {
this.metaFile = metaFile;
}
public String getEntityId() {
return entityId;
}
public void setEntityId(final String entityId) {
this.entityId = entityId;
}
}
public static class Keystore {
private String file;
private String storePassword;
private String keyAlias;
private String keyPassword;
public String getFile() {
return file;
}
public void setFile(final String file) {
this.file = file;
}
public String getStorePassword() {
return storePassword;
}
public void setStorePassword(final String storePassword) {
this.storePassword = storePassword;
}
public String getKeyAlias() {
return keyAlias;
}
public void setKeyAlias(final String keyAlias) {
this.keyAlias = keyAlias;
}
public String getKeyPassword() {
return keyPassword;
}
public void setKeyPassword(final String keyPassword) {
this.keyPassword = keyPassword;
}
}
private boolean enabled;
private Idp idp;
private Sp sp;
private Keystore keystore;
private String userIdAttribute;
private int assertionConsumerServiceIndex;
private int maxAuthenticationLifetime;
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public Idp getIdp() {
return idp;
}
public void setIdp(final Idp idp) {
this.idp = idp;
}
public Sp getSp() {
return sp;
}
public void setSp(final Sp sp) {
this.sp = sp;
}
public Keystore getKeystore() {
return keystore;
}
public void setKeystore(final Keystore keystore) {
this.keystore = keystore;
}
public String getUserIdAttribute() {
return userIdAttribute;
}
public void setUserIdAttribute(final String userIdAttribute) {
this.userIdAttribute = userIdAttribute;
}
public int getAssertionConsumerServiceIndex() {
return assertionConsumerServiceIndex;
}
public void setAssertionConsumerServiceIndex(final int assertionConsumerServiceIndex) {
this.assertionConsumerServiceIndex = assertionConsumerServiceIndex;
}
public int getMaxAuthenticationLifetime() {
return maxAuthenticationLifetime;
}
public void setMaxAuthenticationLifetime(final int maxAuthenticationLifetime) {
this.maxAuthenticationLifetime = maxAuthenticationLifetime;
}
}
public static class Cas extends Provider {
private String hostUrl;
public String getHostUrl() {
return hostUrl;
}
public void setHostUrl(final String hostUrl) {
this.hostUrl = hostUrl;
}
}
public static class Oauth extends Provider {
private String key;
private String secret;
public String getKey() {
return key;
}
public void setKey(final String key) {
this.key = key;
}
public String getSecret() {
return secret;
}
public void setSecret(final String secret) {
this.secret = secret;
}
@Override
public String toString() {
return new ToStringCreator(this).append("enabled", isEnabled()).append("key", key).toString();
}
}
private Registered registered;
private Guest guest;
private List<Ldap> ldap;
private List<Oidc> oidc;
private Saml saml;
private Cas cas;
private Map<String, Oauth> oauth;
public Registered getRegistered() {
return registered;
}
public void setRegistered(final Registered registered) {
this.registered = registered;
}
public Guest getGuest() {
return guest;
}
public void setGuest(final Guest guest) {
this.guest = guest;
}
public List<Ldap> getLdap() {
return ldap;
}
public void setLdap(final List<Ldap> ldap) {
this.ldap = ldap;
}
public List<Oidc> getOidc() {
return oidc;
}
public void setOidc(final List<Oidc> oidc) {
this.oidc = oidc;
}
public Saml getSaml() {
return saml;
}
public void setSaml(final Saml saml) {
this.saml = saml;
}
public Cas getCas() {
return cas;
}
public void setCas(final Cas cas) {
this.cas = cas;
}
public Map<String, Oauth> getOauth() {
return oauth;
}
public void setOauth(final Map<String, Oauth> oauth) {
this.oauth = oauth;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(CouchDbProperties.PREFIX)
public class CouchDbProperties {
public static final String PREFIX = SystemProperties.PREFIX + ".couchdb";
private String host;
private int port;
private String dbName;
private String username;
private String password;
private String migrateFrom;
public String getHost() {
return host;
}
public void setHost(final String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(final int port) {
this.port = port;
}
public String getDbName() {
return dbName;
}
public void setDbName(final String dbName) {
this.dbName = dbName;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
public String getMigrateFrom() {
return migrateFrom;
}
public void setMigrateFrom(final String migrateFrom) {
this.migrateFrom = migrateFrom;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import com.fasterxml.jackson.annotation.JsonView;
import org.springframework.boot.context.properties.ConfigurationProperties;
import de.thm.arsnova.model.serialization.View;
@ConfigurationProperties(FeatureProperties.PREFIX)
public class FeatureProperties {
public static final String PREFIX = "features";
public static class Contents {
private boolean enabled;
private int answerOptionLimit;
@JsonView(View.Public.class)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
@JsonView(View.Public.class)
public int getAnswerOptionLimit() {
return answerOptionLimit;
}
public void setAnswerOptionLimit(final int answerOptionLimit) {
this.answerOptionLimit = answerOptionLimit;
}
}
public static class Comments {
private boolean enabled;
@JsonView(View.Public.class)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
}
public static class LiveFeedback {
private boolean enabled;
private int resetInterval;
@JsonView(View.Public.class)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public int getResetInterval() {
return resetInterval;
}
public void setResetInterval(final int resetInterval) {
this.resetInterval = resetInterval;
}
}
public static class ContentPool {
private boolean enabled;
@JsonView(View.Public.class)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
}
private Contents contents;
private Comments comments;
private LiveFeedback liveFeedback;
private ContentPool contentPool;
@JsonView(View.Public.class)
public Contents getContents() {
return contents;
}
public void setContents(final Contents contents) {
this.contents = contents;
}
@JsonView(View.Public.class)
public Comments getComments() {
return comments;
}
public void setComments(final Comments comments) {
this.comments = comments;
}
@JsonView(View.Public.class)
public LiveFeedback getLiveFeedback() {
return liveFeedback;
}
public void setLiveFeedback(final LiveFeedback liveFeedback) {
this.liveFeedback = liveFeedback;
}
@JsonView(View.Public.class)
public ContentPool getContentPool() {
return contentPool;
}
public void setContentPool(final ContentPool contentPool) {
this.contentPool = contentPool;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(MessageBrokerProperties.PREFIX)
public class MessageBrokerProperties {
public static final String PREFIX = SystemProperties.PREFIX + ".message-broker";
public static class Relay {
private boolean enabled;
private String host;
private int port;
private String username;
private String password;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public String getHost() {
return host;
}
public void setHost(final String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(final int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}
private Relay relay;
public Relay getRelay() {
return relay;
}
public void setRelay(final Relay relay) {
this.relay = relay;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;
@ConfigurationProperties(SecurityProperties.PREFIX)
public class SecurityProperties {
public static final String PREFIX = "security";
public static class Jwt {
private String serverId;
private String secret;
@DurationUnit(ChronoUnit.MINUTES)
private Duration validityPeriod;
public String getServerId() {
return serverId;
}
public void setServerId(final String serverId) {
this.serverId = serverId;
}
public String getSecret() {
return secret;
}
public void setSecret(final String secret) {
this.secret = secret;
}
public Duration getValidityPeriod() {
return validityPeriod;
}
public void setValidityPeriod(final Duration validityPeriod) {
this.validityPeriod = validityPeriod;
}
}
private Jwt jwt;
private List<String> adminAccounts;
private int loginTryLimit;
private List<String> corsOrigins;
public Jwt getJwt() {
return jwt;
}
public void setJwt(final Jwt jwt) {
this.jwt = jwt;
}
public List<String> getAdminAccounts() {
return adminAccounts;
}
public void setAdminAccounts(final List<String> adminAccounts) {
this.adminAccounts = adminAccounts;
}
public int getLoginTryLimit() {
return loginTryLimit;
}
public void setLoginTryLimit(final int loginTryLimit) {
this.loginTryLimit = loginTryLimit;
}
public List<String> getCorsOrigins() {
return corsOrigins;
}
public void setCorsOrigins(final List<String> corsOrigins) {
this.corsOrigins = corsOrigins;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(SystemProperties.PREFIX)
public class SystemProperties {
public static final String PREFIX = "system";
public static class Api {
private String proxyPath;
private boolean indentResponseBody;
private boolean exposeErrorMessages;
public String getProxyPath() {
return proxyPath;
}
public void setProxyPath(final String proxyPath) {
this.proxyPath = proxyPath;
}
public boolean isIndentResponseBody() {
return indentResponseBody;
}
public void setIndentResponseBody(final boolean indentResponseBody) {
this.indentResponseBody = indentResponseBody;
}
public boolean isExposeErrorMessages() {
return exposeErrorMessages;
}
public void setExposeErrorMessages(final boolean exposeErrorMessages) {
this.exposeErrorMessages = exposeErrorMessages;
}
}
public static class Mail {
private String senderName;
private String senderAddress;
private String host;
public String getSenderName() {
return senderName;
}
public void setSenderName(final String senderName) {
this.senderName = senderName;
}
public String getSenderAddress() {
return senderAddress;
}
public void setSenderAddress(final String senderAddress) {
this.senderAddress = senderAddress;
}
public String getHost() {
return host;
}
public void setHost(final String host) {
this.host = host;
}
}
public static class LmsConnector {
private boolean enabled;
private String hostUrl;
private String username;
private String password;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public String getHostUrl() {
return hostUrl;
}
public void setHostUrl(final String hostUrl) {
this.hostUrl = hostUrl;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}
public static class Socketio {
private String bindAddress;
private int port;
private String proxyPath;
public String getBindAddress() {
return bindAddress;
}
public void setBindAddress(final String bindAddress) {
this.bindAddress = bindAddress;
}
public int getPort() {
return port;
}
public void setPort(final int port) {
this.port = port;
}
public String getProxyPath() {
return proxyPath;
}
public void setProxyPath(final String proxyPath) {
this.proxyPath = proxyPath;
}
}
private String rootUrl;
private Api api;
private Mail mail;
private LmsConnector lmsConnector;
private Socketio socketio;
public String getRootUrl() {
return rootUrl;
}
public void setRootUrl(final String rootUrl) {
this.rootUrl = rootUrl;
}
public Api getApi() {
return api;
}
public void setApi(final Api api) {
this.api = api;
}
public Mail getMail() {
return mail;
}
public void setMail(final Mail mail) {
this.mail = mail;
}
public LmsConnector getLmsConnector() {
return lmsConnector;
}
public void setLmsConnector(final LmsConnector lmsConnector) {
this.lmsConnector = lmsConnector;
}
public Socketio getSocketio() {
return socketio;
}
public void setSocketio(final Socketio socketio) {
this.socketio = socketio;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,23 +15,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.socket.message;
public class Question {
package de.thm.arsnova.config.properties;
private final String _id;
private final String variant;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
public Question(de.thm.arsnova.entities.Question question) {
this._id = question.get_id();
this.variant = question.getQuestionVariant();
}
@ConfigurationProperties
public class UiProperties {
private Map<String, Object> ui;
public String get_id() {
return _id;
public Map<String, Object> getUi() {
return ui;
}
public String getVariant() {
return variant;
public void setUi(final Map<String, Object> ui) {
this.ui = ui;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,9 +15,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
/**
* Base class of all controllers.
*/
public class AbstractController {
protected static final String X_DEPRECATED_API = "X-Deprecated-API";
protected static final String X_FORWARDED = "X-Forwarded";
protected static final String HTML_STATUS_200 = "OK";
protected static final String HTML_STATUS_201 = "Created";
protected static final String HTML_STATUS_204 = "No Content";
protected static final String HTML_STATUS_400 = "Bad request";
protected static final String HTML_STATUS_403 = "Forbidden";
protected static final String HTML_STATUS_404 = "Not Found";
protected static final String HTML_STATUS_501 = "Not Implemented";
protected static final String HTML_STATUS_503 = "Service Unavailable";
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.naming.OperationNotSupportedException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.util.UriComponentsBuilder;
import de.thm.arsnova.model.Entity;
import de.thm.arsnova.model.FindQuery;
import de.thm.arsnova.service.EntityService;
import de.thm.arsnova.service.FindQueryService;
import de.thm.arsnova.web.exceptions.NotFoundException;
/**
* Base type for Entity controllers which provides basic CRUD operations and supports Entity patching.
*
* @param <E> Entity type
* @author Daniel Gerhardt
*/
public abstract class AbstractEntityController<E extends Entity> {
public static final String MEDIATYPE_EMPTY = "application/x-empty";
private static final Logger logger = LoggerFactory.getLogger(AbstractEntityController.class);
protected static final String ENTITY_ID_HEADER = "Arsnova-Entity-Id";
protected static final String ENTITY_REVISION_HEADER = "Arsnova-Entity-Revision";
protected static final String DEFAULT_ROOT_MAPPING = "/";
protected static final String DEFAULT_ID_MAPPING = "/{id:[^~].*}";
protected static final String DEFAULT_ALIAS_MAPPING = "/~{alias}";
protected static final String DEFAULT_FIND_MAPPING = "/find";
protected static final String ALIAS_SUBPATH = "/{subPath:.+}";
protected static final String GET_MAPPING = DEFAULT_ID_MAPPING;
protected static final String GET_MULTIPLE_MAPPING = DEFAULT_ROOT_MAPPING;
protected static final String PUT_MAPPING = DEFAULT_ID_MAPPING;
protected static final String POST_MAPPING = DEFAULT_ROOT_MAPPING;
protected static final String PATCH_MAPPING = DEFAULT_ID_MAPPING;
protected static final String DELETE_MAPPING = DEFAULT_ID_MAPPING;
protected static final String FIND_MAPPING = DEFAULT_FIND_MAPPING;
protected final EntityService<E> entityService;
protected FindQueryService<E> findQueryService;
protected AbstractEntityController(final EntityService<E> entityService) {
this.entityService = entityService;
}
protected abstract String getMapping();
@GetMapping(GET_MAPPING)
public E get(@PathVariable final String id) {
return entityService.get(id);
}
@GetMapping(GET_MULTIPLE_MAPPING)
public Iterable<E> getMultiple(@RequestParam final Collection<String> ids) {
return entityService.get(ids);
}
@PutMapping(value = PUT_MAPPING, produces = MEDIATYPE_EMPTY)
public void putWithoutResponse(@RequestBody final E entity, final HttpServletResponse httpServletResponse) {
put(entity, httpServletResponse);
}
@PutMapping(PUT_MAPPING)
public E put(@RequestBody final E entity, final HttpServletResponse httpServletResponse) {
final E oldEntity = entityService.get(entity.getId());
entityService.update(oldEntity, entity);
httpServletResponse.setHeader(ENTITY_ID_HEADER, entity.getId());
httpServletResponse.setHeader(ENTITY_REVISION_HEADER, entity.getRevision());
return entity;
}
@PostMapping(value = POST_MAPPING, produces = MEDIATYPE_EMPTY)
@ResponseStatus(HttpStatus.CREATED)
public void postWithoutResponse(@RequestBody final E entity, final HttpServletResponse httpServletResponse) {
post(entity, httpServletResponse);
}
@PostMapping(POST_MAPPING)
@ResponseStatus(HttpStatus.CREATED)
public E post(@RequestBody final E entity, final HttpServletResponse httpServletResponse) {
entityService.create(entity);
final String uri = UriComponentsBuilder.fromPath(getMapping()).path(GET_MAPPING)
.buildAndExpand(entity.getId()).toUriString();
httpServletResponse.setHeader(HttpHeaders.LOCATION, uri);
httpServletResponse.setHeader(ENTITY_ID_HEADER, entity.getId());
httpServletResponse.setHeader(ENTITY_REVISION_HEADER, entity.getRevision());
return entity;
}
@PatchMapping(value = PATCH_MAPPING, produces = MEDIATYPE_EMPTY)
public void patchWithoutResponse(@PathVariable final String id, @RequestBody final Map<String, Object> changes,
final HttpServletResponse httpServletResponse) throws IOException {
patch(id, changes, httpServletResponse);
}
@PatchMapping(PATCH_MAPPING)
public E patch(@PathVariable final String id, @RequestBody final Map<String, Object> changes,
final HttpServletResponse httpServletResponse) throws IOException {
final E entity = entityService.get(id);
entityService.patch(entity, changes);
httpServletResponse.setHeader(ENTITY_ID_HEADER, entity.getId());
httpServletResponse.setHeader(ENTITY_REVISION_HEADER, entity.getRevision());
return entity;
}
@DeleteMapping(DELETE_MAPPING)
public void delete(@PathVariable final String id) {
final E entity = entityService.get(id);
entityService.delete(entity);
}
@PostMapping(FIND_MAPPING)
public Iterable<E> find(@RequestBody final FindQuery<E> findQuery) throws OperationNotSupportedException {
if (findQueryService != null) {
logger.debug("Resolving find query: {}", findQuery);
final Set<String> ids = findQueryService.resolveQuery(findQuery);
logger.debug("Resolved find query to IDs: {}", ids);
return entityService.get(ids);
} else {
throw new OperationNotSupportedException("Find is not supported for this entity type.");
}
}
@RequestMapping(value = {DEFAULT_ALIAS_MAPPING, DEFAULT_ALIAS_MAPPING + ALIAS_SUBPATH})
public void forwardAlias(@PathVariable final String alias, @PathVariable(required = false) final String subPath,
final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
throws ServletException, IOException {
final String targetPath = String.format(
"%s/%s%s", getMapping(), resolveAlias(alias), subPath != null ? "/" + subPath : "");
logger.debug("Forwarding alias request to {}", targetPath);
httpServletRequest.getRequestDispatcher(targetPath)
.forward(httpServletRequest, httpServletResponse);
}
protected String resolveAlias(final String alias) {
throw new NotFoundException("Aliases not supported for " + getMapping() + ".");
}
@Autowired(required = false)
public void setFindQueryService(final FindQueryService<E> findQueryService) {
this.findQueryService = findQueryService;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,35 +15,29 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.events;
import de.thm.arsnova.entities.InterposedQuestion;
import de.thm.arsnova.entities.Session;
package de.thm.arsnova.controller;
public class NewInterposedQuestionEvent extends NovaEvent {
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
private static final long serialVersionUID = 1L;
import de.thm.arsnova.model.Answer;
import de.thm.arsnova.service.AnswerService;
private final Session session;
private final InterposedQuestion question;
@RestController
@RequestMapping(AnswerController.REQUEST_MAPPING)
public class AnswerController extends AbstractEntityController<Answer> {
protected static final String REQUEST_MAPPING = "/answer";
public NewInterposedQuestionEvent(Object source, InterposedQuestion question, Session session) {
super(source);
this.question = question;
this.session = session;
}
public Session getSession() {
return session;
}
private AnswerService answerService;
public InterposedQuestion getQuestion() {
return question;
public AnswerController(final AnswerService answerService) {
super(answerService);
this.answerService = answerService;
}
@Override
public void accept(NovaEventVisitor visitor) {
visitor.visit(this);
protected String getMapping() {
return REQUEST_MAPPING;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import de.thm.arsnova.entities.transport.InterposedQuestion;
import de.thm.arsnova.entities.InterposedReadingCount;
import de.thm.arsnova.exceptions.BadRequestException;
import de.thm.arsnova.services.IQuestionService;
import de.thm.arsnova.web.DeprecatedApi;
@RestController
@RequestMapping("/audiencequestion")
public class AudienceQuestionController extends AbstractController {
public static final Logger LOGGER = LoggerFactory.getLogger(AudienceQuestionController.class);
@Autowired
private IQuestionService questionService;
@RequestMapping(value = "/count", method = RequestMethod.GET)
@DeprecatedApi
public final int getInterposedCount(@RequestParam final String sessionkey) {
return questionService.getInterposedCount(sessionkey);
}
@RequestMapping(value = "/readcount", method = RequestMethod.GET)
@DeprecatedApi
public final InterposedReadingCount getUnreadInterposedCount(@RequestParam("sessionkey") final String sessionkey) {
return questionService.getInterposedReadingCount(sessionkey);
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public final List<InterposedQuestion> getInterposedQuestions(@RequestParam final String sessionkey) {
return InterposedQuestion.fromList(questionService.getInterposedQuestions(sessionkey));
}
@RequestMapping(value = "/{questionId}", method = RequestMethod.GET)
public final InterposedQuestion getInterposedQuestion(@PathVariable final String questionId) {
return new InterposedQuestion(questionService.readInterposedQuestion(questionId));
}
@RequestMapping(value = "/", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public final void postInterposedQuestion(
@RequestParam final String sessionkey,
@RequestBody final de.thm.arsnova.entities.InterposedQuestion question
) {
if (questionService.saveQuestion(question)) {
return;
}
throw new BadRequestException();
}
@RequestMapping(value = "/{questionId}", method = RequestMethod.DELETE)
public final void deleteInterposedQuestion(@PathVariable final String questionId) {
questionService.deleteInterposedQuestion(questionId);
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.pac4j.core.context.J2EContext;
import org.pac4j.oidc.client.OidcClient;
import org.pac4j.saml.client.SAML2Client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;
import de.thm.arsnova.config.SecurityConfig;
import de.thm.arsnova.model.ClientAuthentication;
import de.thm.arsnova.model.LoginCredentials;
import de.thm.arsnova.model.UserProfile;
import de.thm.arsnova.security.LoginAuthenticationSucessHandler;
import de.thm.arsnova.service.UserService;
import de.thm.arsnova.web.exceptions.NotImplementedException;
@RestController
@RequestMapping("/auth")
public class AuthenticationController {
private UserService userService;
private OidcClient oidcClient;
private SAML2Client saml2Client;
private CasAuthenticationEntryPoint casEntryPoint;
public AuthenticationController(final UserService userService) {
this.userService = userService;
}
@Autowired(required = false)
public void setOidcClient(final OidcClient oidcClient) {
this.oidcClient = oidcClient;
}
@Autowired(required = false)
public void setSaml2Client(final SAML2Client saml2Client) {
this.saml2Client = saml2Client;
}
@Autowired(required = false)
public void setCasEntryPoint(final CasAuthenticationEntryPoint casEntryPoint) {
this.casEntryPoint = casEntryPoint;
}
@PostMapping("/login")
public ClientAuthentication login(@RequestParam(defaultValue = "false") final boolean refresh,
final HttpServletRequest request, final HttpServletResponse response) {
if (request.getCookies() != null && Arrays.stream(request.getCookies())
.anyMatch(c -> c.getName().equalsIgnoreCase(LoginAuthenticationSucessHandler.AUTH_COOKIE_NAME))) {
/* Delete cookie */
final Cookie cookie = new Cookie(LoginAuthenticationSucessHandler.AUTH_COOKIE_NAME, null);
cookie.setPath(request.getContextPath());
cookie.setMaxAge(0);
response.addCookie(cookie);
}
return userService.getCurrentClientAuthentication(refresh);
}
@PostMapping("/login/guest")
public ClientAuthentication loginGuest(final HttpServletRequest request) {
final ClientAuthentication currentAuthentication = userService.getCurrentClientAuthentication(false);
if (currentAuthentication != null
&& currentAuthentication.getAuthProvider() == UserProfile.AuthProvider.ARSNOVA_GUEST) {
return currentAuthentication;
}
userService.authenticate(new UsernamePasswordAuthenticationToken(null, null),
UserProfile.AuthProvider.ARSNOVA_GUEST, request.getRemoteAddr());
return userService.getCurrentClientAuthentication(false);
}
@PostMapping("/login/{providerId}")
public ClientAuthentication loginViaProvider(
@PathVariable final String providerId,
@RequestBody final LoginCredentials loginCredentials,
final HttpServletRequest request) {
switch (providerId) {
case "registered":
final String loginId = loginCredentials.getLoginId().toLowerCase();
userService.authenticate(new UsernamePasswordAuthenticationToken(
loginId, loginCredentials.getPassword()),
UserProfile.AuthProvider.ARSNOVA, request.getRemoteAddr());
return userService.getCurrentClientAuthentication(false);
case SecurityConfig.LDAP_PROVIDER_ID:
userService.authenticate(new UsernamePasswordAuthenticationToken(
loginCredentials.getLoginId(), loginCredentials.getPassword()),
UserProfile.AuthProvider.LDAP, request.getRemoteAddr());
return userService.getCurrentClientAuthentication(false);
default:
throw new IllegalArgumentException("Invalid provider ID.");
}
}
@GetMapping("/sso/{providerId}")
public View redirectToSso(@PathVariable final String providerId,
final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
switch (providerId) {
case SecurityConfig.OIDC_PROVIDER_ID:
if (oidcClient == null) {
throw new IllegalArgumentException("Invalid provider ID.");
}
return new RedirectView(
oidcClient.getRedirectAction(new J2EContext(request, response)).getLocation());
case SecurityConfig.SAML_PROVIDER_ID:
if (saml2Client == null) {
throw new IllegalArgumentException("Invalid provider ID.");
}
return new RedirectView(
saml2Client.getRedirectAction(new J2EContext(request, response)).getLocation());
case SecurityConfig.CAS_PROVIDER_ID:
if (casEntryPoint == null) {
throw new IllegalArgumentException("Invalid provider ID.");
}
casEntryPoint.commence(request, response, null);
return null;
default:
throw new IllegalArgumentException("Invalid provider ID.");
}
}
@GetMapping(value = "/config/saml/sp-metadata.xml", produces = MediaType.APPLICATION_XML_VALUE)
public String samlSpMetadata() throws IOException {
if (saml2Client == null) {
throw new NotImplementedException("SAML authentication is disabled.");
}
return saml2Client.getServiceProviderMetadataResolver().getMetadata();
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.thm.arsnova.model.Comment;
import de.thm.arsnova.service.CommentService;
@RestController
@RequestMapping(CommentController.REQUEST_MAPPING)
public class CommentController extends AbstractEntityController<Comment> {
protected static final String REQUEST_MAPPING = "/comment";
private CommentService commentService;
public CommentController(final CommentService commentService) {
super(commentService);
this.commentService = commentService;
}
@Override
protected String getMapping() {
return REQUEST_MAPPING;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2015 The ARSnova Team
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,216 +15,90 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.controller;
import java.util.ArrayList;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* The ConfigurationController provides frontend clients with information necessary to correctly interact with the
* backend and other frontends as well as settings for ARSnova. The the alternative /arsnova-config route is necessary
* in case the backend application is deployed as root context.
*/
@Controller
@RequestMapping({"/configuration", "/arsnova-config"})
public class ConfigurationController extends AbstractController {
@Value("${security.guest.enabled}")
private String guestEnabled;
public static final Logger LOGGER = LoggerFactory
.getLogger(ConfigurationController.class);
@Value("${api.path:}")
private String apiPath;
@Value("${customization.path}")
private String customizationPath;
@Value("${mobile.path}")
private String mobilePath;
@Value("${presenter.path}")
private String presenterPath;
@Value("${links.overlay.url}")
private String overlayUrl;
@Value("${links.organization.url}")
private String organizationUrl;
@Value("${links.imprint.url}")
private String imprintUrl;
@Value("${links.blog.url:}")
private String blogUrl;
@Value("${links.privacy-policy.url}")
private String privacyPolicyUrl;
@Value("${links.documentation.url}")
private String documentationUrl;
@Value("${links.presenter-documentation.url}")
private String presenterDocumentationUrl;
@Value("${features.mathjax.enabled:true}")
private String mathJaxEnabled;
@Value("${features.markdown.enabled:false}")
private String markdownEnabled;
@Value("${features.learning-progress.enabled:false}")
private String learningProgressEnabled;
@Value("${features.students-own-questions.enabled:false}")
private String studentsOwnQuestions;
@Value("${features.question-format.flashcard.enabled:false}")
private String flashcardEnabled;
@Value("${features.question-format.grid-square.enabled:false}")
private String gridSquareEnabled;
@Value("${features.session-import-export.enabled:false}")
private String sessionImportExportEnabled;
@Value("${features.public-pool.enabled:false}")
private String publicPoolEnabled;
@Value("${question.answer-option-limit:8}")
private String answerOptionLimit;
@Value("${upload.filesize_b:}")
private String maxUploadFilesize;
@Value("${question.parse-answer-option-formatting:false}")
private String parseAnswerOptionFormatting;
@Value("${pp.subjects}")
private String ppSubjects;
@Value("${pp.licenses}")
private String ppLicenses;
@Value("${pp.logofilesize_b}")
private String ppLogoMaxFilesize;
@Value("${upload.filesize_b}")
private String gridImageMaxFileSize;
@Value("${tracking.provider}")
private String trackingProvider;
@Value("${tracking.tracker-url}")
private String trackingTrackerUrl;
@Value("${tracking.site-id}")
private String trackingSiteId;
@Value("${optional.demoSessionKey:}")
private String demoSessionKey;
@Value("${pp.session-levels.de}")
private String ppLevelsDe;
@Value("${pp.session-levels.en}")
private String ppLevelsEn;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public final HashMap<String, Object> getConfiguration(HttpServletRequest request) {
HashMap<String, Object> config = new HashMap<String, Object>();
HashMap<String, Boolean> features = new HashMap<String, Boolean>();
HashMap<String, String> publicPool = new HashMap<String, String>();
import org.springframework.web.bind.annotation.RestController;
import de.thm.arsnova.config.SecurityConfig;
import de.thm.arsnova.config.properties.AuthenticationProviderProperties;
import de.thm.arsnova.config.properties.FeatureProperties;
import de.thm.arsnova.config.properties.UiProperties;
import de.thm.arsnova.model.AuthenticationProvider;
import de.thm.arsnova.model.Configuration;
@RestController
@RequestMapping(ConfigurationController.REQUEST_MAPPING)
@EnableConfigurationProperties(UiProperties.class)
public class ConfigurationController {
protected static final String REQUEST_MAPPING = "/configuration";
private AuthenticationProviderProperties providerProperties;
private UiProperties uiProperties;
private FeatureProperties featureProperties;
private List<AuthenticationProvider> authenticationProviders;
private Map<String, Object> featureConfig;
public ConfigurationController(
final AuthenticationProviderProperties authenticationProviderProperties,
final UiProperties uiProperties,
final FeatureProperties featureProperties) {
this.providerProperties = authenticationProviderProperties;
this.uiProperties = uiProperties;
this.featureProperties = featureProperties;
buildAuthenticationProviderConfig();
buildFeatureConfig();
}
/* The API path could be unknown to the client in case the request was forwarded */
if ("".equals(apiPath)) {
apiPath = request.getContextPath();
}
config.put("apiPath", apiPath);
@GetMapping
public Configuration get() {
final Configuration configuration = new Configuration();
configuration.setAuthenticationProviders(authenticationProviders);
configuration.setUi(uiProperties.getUi());
configuration.setFeatures(featureConfig);
if (!"".equals(customizationPath)) {
config.put("customizationPath", customizationPath);
}
if (!"".equals(mobilePath)) {
config.put("mobilePath", mobilePath);
}
if (!"".equals(presenterPath)) {
config.put("presenterPath", presenterPath);
}
return configuration;
}
if (!"".equals(documentationUrl)) {
config.put("documentationUrl", documentationUrl);
}
if (!"".equals(blogUrl)) {
config.put("blogUrl", blogUrl);
}
if (!"".equals(presenterDocumentationUrl)) {
config.put("presenterDocumentationUrl", presenterDocumentationUrl);
}
if (!"".equals(overlayUrl)) {
config.put("overlayUrl", overlayUrl);
private void buildAuthenticationProviderConfig() {
this.authenticationProviders = new ArrayList<>();
if (providerProperties.getGuest().isEnabled()) {
authenticationProviders.add(new AuthenticationProvider("guest", providerProperties.getGuest()));
}
if (!"".equals(organizationUrl)) {
config.put("organizationUrl", organizationUrl);
if (providerProperties.getRegistered().isEnabled()) {
authenticationProviders.add(new AuthenticationProvider(
SecurityConfig.INTERNAL_PROVIDER_ID, providerProperties.getRegistered()));
}
if (!"".equals(imprintUrl)) {
config.put("imprintUrl", imprintUrl);
if (!providerProperties.getLdap().isEmpty() && providerProperties.getLdap().get(0).isEnabled()) {
authenticationProviders.add(new AuthenticationProvider(
SecurityConfig.LDAP_PROVIDER_ID, providerProperties.getLdap().get(0)));
}
if (!"".equals(privacyPolicyUrl)) {
config.put("privacyPolicyUrl", privacyPolicyUrl);
if (!providerProperties.getOidc().isEmpty() && providerProperties.getOidc().get(0).isEnabled()) {
authenticationProviders.add(new AuthenticationProvider(
SecurityConfig.OIDC_PROVIDER_ID, providerProperties.getOidc().get(0)));
}
if (!"".equals(demoSessionKey)) {
config.put("demoSessionKey", demoSessionKey);
}
if (!"".equals(maxUploadFilesize)) {
config.put("maxUploadFilesize", maxUploadFilesize);
}
config.put("answerOptionLimit", Integer.valueOf(answerOptionLimit));
config.put("parseAnswerOptionFormatting", Boolean.valueOf(parseAnswerOptionFormatting));
config.put("features", features);
features.put("mathJax", "true".equals(mathJaxEnabled));
features.put("markdown", "true".equals(markdownEnabled));
features.put("learningProgress", "true".equals(learningProgressEnabled));
features.put("studentsOwnQuestions", "true".equals(studentsOwnQuestions));
features.put("flashcard", "true".equals(flashcardEnabled));
features.put("gridSquare", "true".equals(gridSquareEnabled));
features.put("sessionImportExport", "true".equals(sessionImportExportEnabled));
features.put("publicPool", "true".equals(publicPoolEnabled));
// add public pool configuration on demand
if (features.get("publicPool")) {
config.put("publicPool", publicPool);
publicPool.put("subjects", ppSubjects);
publicPool.put("licenses", ppLicenses);
publicPool.put("logoMaxFilesize", ppLogoMaxFilesize);
publicPool.put("levelsDe", ppLevelsDe);
publicPool.put("levelsEn", ppLevelsEn);
if (providerProperties.getSaml().isEnabled()) {
authenticationProviders.add(new AuthenticationProvider(
SecurityConfig.SAML_PROVIDER_ID, providerProperties.getSaml()));
}
if (!"".equals(trackingTrackerUrl)) {
HashMap<String, String> tracking = new HashMap<String, String>();
config.put("tracking", tracking);
tracking.put("provider", trackingProvider);
tracking.put("trackerUrl", trackingTrackerUrl);
tracking.put("siteId", trackingSiteId);
if (providerProperties.getCas().isEnabled()) {
authenticationProviders.add(new AuthenticationProvider(
SecurityConfig.CAS_PROVIDER_ID, providerProperties.getCas()));
}
}
config.put("grid", gridImageMaxFileSize);
return config;
private void buildFeatureConfig() {
this.featureConfig = new HashMap<>();
featureConfig.put("contents", featureProperties.getContents());
featureConfig.put("comments", featureProperties.getComments());
featureConfig.put("liveFeedback", featureProperties.getLiveFeedback());
featureConfig.put("contentPool", featureProperties.getContentPool());
}
}