Commit 290c1b85 authored by Daniel Gerhardt's avatar Daniel Gerhardt

Remove internal database for auth and config

This feature seems to be overkill for the LMS Connector's use case and
has never been used in production.

We remove it because:
* it increased creates code maintenance overhead
* the integrated database increases the the memory footprint
parent 533a43cb
......@@ -24,16 +24,11 @@ dependencies {
compile group: 'org.springframework', name: 'spring-context', version: springVersion
compile group: 'org.springframework', name: 'spring-webmvc', version: springVersion
compile group: 'org.springframework', name: 'spring-jdbc', version: springVersion
compile group: 'org.springframework', name: 'spring-tx', version: springVersion
compile group: 'org.springframework', name: 'spring-orm', version: springVersion
compile group: 'org.springframework.data', name: 'spring-data-jpa', version: '1.7.2.RELEASE'
compile group: 'org.springframework.security', name: 'spring-security-web', version: springSecurityVersion
compile group: 'org.springframework.security', name: 'spring-security-config', version: springSecurityVersion
compile group: 'org.springframework.security', name: 'spring-security-ldap', version: springSecurityVersion
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.34'
compile group: 'org.hsqldb', name: 'hsqldb', version: '2.3.2'
compile group: 'cglib', name: 'cglib', version: '3.1'
compile group: 'org.apache.openjpa', name: 'openjpa', version: '2.3.0'
compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.10'
compile group: 'org.json', name: 'json', version: '20141113'
......@@ -42,6 +37,7 @@ dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.mockito', name: 'mockito-core', version: '1.10.19'
testCompile group: 'org.dbunit', name: 'dbunit', version: '2.5.0'
testCompile group: 'org.hsqldb', name: 'hsqldb', version: '2.3.2'
}
test { systemProperties 'property': 'value' }
......
......@@ -2,12 +2,13 @@ package de.thm.arsnova.connector.auth;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.Authentication;
......@@ -15,13 +16,10 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import de.thm.arsnova.connector.persistence.domain.User;
import de.thm.arsnova.connector.persistence.repository.UserRepository;
@Service
public class AuthenticationTokenService {
@Autowired
private UserRepository userRep;
private Map<String, User> tokenToUserMappings = new HashMap<>();
public final String HEADER_SECURITY_TOKEN = "X-Auth-Token";
......@@ -53,7 +51,7 @@ public class AuthenticationTokenService {
User user = null;
if(token != null) {
user = userRep.findByToken(token);
user = tokenToUserMappings.get(token);
}
return user;
......@@ -83,16 +81,13 @@ public class AuthenticationTokenService {
* @return The authentication token string.
*/
private String createAndStoreToken(UserDetails ud) {
User user = userRep.findOne(ud.getUsername());
String token = generateToken(ud);
if(user == null) {
user = new User();
user.setUserId(ud.getUsername());
}
User user = new User();
user.setUserId(ud.getUsername());
user.setAuthToken(token);
userRep.save(user);
tokenToUserMappings.put(token, user);
return token;
}
......
package de.thm.arsnova.connector.config;
import java.sql.SQLException;
import java.util.Properties;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
......@@ -12,13 +9,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import de.thm.arsnova.connector.dao.ConnectorDao;
......@@ -27,7 +18,6 @@ import de.thm.arsnova.connector.dao.ConnectorDao;
"de.thm.arsnova.connector.services"
})
@Configuration
@EnableJpaRepositories("de.thm.arsnova.connector.persistence.repository")
@PropertySource("file:///etc/arsnova/connector.properties")
public class AppConfig {
......@@ -49,58 +39,8 @@ public class AppConfig {
return dataSource;
}
@Bean(name = "configDataSource")
public HsqlDataSource configDataSource() throws SQLException {
HsqlDataSource dataSource = new HsqlDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbc.JDBCDriver");
dataSource.setUrl("jdbc:hsqldb:file:/etc/arsnova/connector.db");
dataSource.setUsername("whatever");
dataSource.setPassword("topsecret");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws SQLException {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(configDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setPackagesToScan("de.thm.arsnova.connector.persistence.domain");
Properties jpaProperties = new Properties();
jpaProperties.put("openjpa.RuntimeUnenhancedClasses", "supported");
lef.setJpaProperties(jpaProperties);
lef.afterPropertiesSet();
return lef;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
OpenJpaVendorAdapter jpaVendorAdapter = new OpenJpaVendorAdapter();
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setGenerateDdl(true);
return jpaVendorAdapter;
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
@Bean
public ConnectorDao connectorDao() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return (ConnectorDao) Class.forName(env.getProperty("dao.implementation")).newInstance();
}
private class HsqlDataSource extends DriverManagerDataSource {
@PreDestroy
public void shutdown() {
logger.info("Shutting down HSQLDB");
try {
this.getConnection().createStatement().execute("SHUTDOWN;");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
......@@ -2,19 +2,11 @@ package de.thm.arsnova.connector.core;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import de.thm.arsnova.connector.persistence.domain.User;
import de.thm.arsnova.connector.services.InternalUserService;
public class RepoPermissionEvaluator implements PermissionEvaluator {
@Autowired
private InternalUserService internalUserService;
@Override
public boolean hasPermission(
final Authentication authentication,
......@@ -58,11 +50,6 @@ public class RepoPermissionEvaluator implements PermissionEvaluator {
}
private boolean isAdmin(final UserDetails user) {
final User u = internalUserService.getUser(user.getUsername());
if (u == null) {
return false;
}
return u.isAdmin();
return false;
}
}
package de.thm.arsnova.connector.persistence.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "configuration")
public class Configuration {
@Id
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
return (this.key + this.value).hashCode();
};
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof Configuration) {
Configuration other = (Configuration) obj;
if (
(this.key != null && this.key.equals(other.getKey()))
&& (this.value != null && this.value.equals(other.getValue()))
) {
return true;
}
}
return false;
}
}
package de.thm.arsnova.connector.persistence.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.openjpa.persistence.jdbc.Unique;
@Entity
@Table(name = "enabled_category")
public class EnabledCategory {
@Id
@Unique
@Column(name = "ref_id")
private int refId;
public int getRefId() {
return refId;
}
public void setRefId(int refId) {
this.refId = refId;
}
}
package de.thm.arsnova.connector.persistence.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.openjpa.persistence.jdbc.Unique;
@Entity
@Table(name = "user")
public class User {
@Id
@Unique
@Column(name = "user_id")
private String userId;
@Column(name = "password")
private String password;
@Column(name = "is_admin")
private boolean isAdmin;
@Unique
@Column(name = "auth_token")
private String authToken;
public String getUserId() {
......
/**
* @author pcvolkmer
*
*/
package de.thm.arsnova.connector.persistence.domain;
\ No newline at end of file
package de.thm.arsnova.connector.persistence.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import de.thm.arsnova.connector.persistence.domain.Configuration;
@Repository
public interface ConfigurationRepository extends JpaRepository<Configuration, String> {
}
package de.thm.arsnova.connector.persistence.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import de.thm.arsnova.connector.persistence.domain.EnabledCategory;
@Repository
public interface EnabledCategoryRepository extends JpaRepository<EnabledCategory, Integer> {
}
package de.thm.arsnova.connector.persistence.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import de.thm.arsnova.connector.persistence.domain.User;
@Repository
public interface UserRepository extends JpaRepository<User, String> {
@Query("select u from User u where u.authToken like %?1")
User findByToken(String authToken);
}
package de.thm.arsnova.connector.services;
import org.springframework.security.access.prepost.PreAuthorize;
import de.thm.arsnova.connector.persistence.domain.Configuration;
public interface ConfigurationService {
@PreAuthorize(value = "hasRole('ADMIN') or hasPermission(#username, 'configuration', 'read')")
Configuration getConfigurationElement(String key);
@PreAuthorize(value = "hasRole('ADMIN') or hasPermission(#username, 'configuration', 'write')")
void setConfigurationElement(Configuration config);
}
package de.thm.arsnova.connector.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.thm.arsnova.connector.persistence.domain.Configuration;
import de.thm.arsnova.connector.persistence.repository.ConfigurationRepository;
@Service
public class ConfigurationServiceImpl implements ConfigurationService {
@Autowired
private ConfigurationRepository repo;
@Override
public Configuration getConfigurationElement(String key) {
return repo.findOne(key);
}
@Override
public void setConfigurationElement(Configuration config) {
repo.save(config);
}
}
package de.thm.arsnova.connector.services;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
import de.thm.arsnova.connector.persistence.domain.EnabledCategory;
public interface EnabledCategoryService {
@PreAuthorize(value = "hasRole('ADMIN') or hasPermission(#username, 'enabled_category', 'write')")
void enableCategory(int refId);
@PreAuthorize(value = "hasRole('ADMIN') or hasPermission(#username, 'enabled_category', 'write')")
void disableCategory(int refId);
List<EnabledCategory> getEnabledCategories();
boolean isEnabledCategory(int refId);
}
package de.thm.arsnova.connector.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.thm.arsnova.connector.persistence.domain.EnabledCategory;
import de.thm.arsnova.connector.persistence.repository.EnabledCategoryRepository;
@Service
public class EnabledCategoryServiceImpl implements EnabledCategoryService {
@Autowired
private EnabledCategoryRepository repo;
@Override
public void enableCategory(int refId) {
EnabledCategory cat = new EnabledCategory();
cat.setRefId(refId);
repo.save(cat);
}
@Override
public void disableCategory(int refId) {
repo.delete(refId);
}
@Override
public List<EnabledCategory> getEnabledCategories() {
return repo.findAll();
}
@Override
public boolean isEnabledCategory(int refId) {
for (EnabledCategory ec : getEnabledCategories()) {
if (ec.getRefId() == refId) {
return true;
}
}
return false;
}
}
package de.thm.arsnova.connector.services;
import org.springframework.security.access.prepost.PreAuthorize;
import de.thm.arsnova.connector.persistence.domain.User;
public interface InternalUserService {
User getUser(String userid);
@PreAuthorize(value = "hasRole('ADMIN')")
void saveUser(User user);
@PreAuthorize(value = "hasRole('ADMIN')")
void makeAdmin(String userid);
@PreAuthorize(value = "hasRole('ADMIN')")
void unmakeAdmin(String userid);
}
package de.thm.arsnova.connector.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.token.Sha512DigestUtils;
import org.springframework.stereotype.Service;
import de.thm.arsnova.connector.persistence.domain.User;
import de.thm.arsnova.connector.persistence.repository.UserRepository;
@Service
public class InternalUserServiceImpl implements InternalUserService {
@Autowired
private UserRepository repo;
@Override
public User getUser(String userid) {
return repo.findOne(userid);
}
@Override
public void saveUser(User user) {
if (! user.getPassword().startsWith("{SHA512}")) {
String password = user.getPassword();
user.setPassword("{SHA512}" + Sha512DigestUtils.shaHex(password));
}
repo.save(user);
}
@Override
public void makeAdmin(String userid) {
User u = getUser(userid);
u.setAdmin(true);
saveUser(u);
}
@Override
public void unmakeAdmin(String userid) {
User u = getUser(userid);
u.setAdmin(false);
saveUser(u);
}
}
package de.thm.arsnova.connector.config;
import java.sql.SQLException;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import de.thm.arsnova.connector.services.ConfigurationService;
import de.thm.arsnova.connector.services.ConfigurationServiceImpl;
import de.thm.arsnova.connector.services.EnabledCategoryService;
import de.thm.arsnova.connector.services.EnabledCategoryServiceImpl;
import de.thm.arsnova.connector.services.InternalUserService;
import de.thm.arsnova.connector.services.InternalUserServiceImpl;
@Configuration
@EnableJpaRepositories("de.thm.arsnova.connector.persistence.repository")
public class RepositoryTestConfig {
@Bean
public ConfigurationService configurationService() {
return new ConfigurationServiceImpl();
}
@Bean
public EnabledCategoryService enabledCategoryService() {
return new EnabledCategoryServiceImpl();
}
@Bean
public InternalUserService internalUserService() {
return new InternalUserServiceImpl();
}
@Bean(name = "configDataSource")
public DriverManagerDataSource configDataSource() throws SQLException {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
......@@ -47,32 +17,4 @@ public class RepositoryTestConfig {
dataSource.setPassword("");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws SQLException {
final LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(configDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setPackagesToScan("de.thm.arsnova.connector.persistence.domain");
final Properties jpaProperties = new Properties();
jpaProperties.put("openjpa.RuntimeUnenhancedClasses", "supported");
lef.setJpaProperties(jpaProperties);
lef.afterPropertiesSet();
return lef;
}
@Bean
public OpenJpaVendorAdapter jpaVendorAdapter() {
final OpenJpaVendorAdapter jpaVendorAdapter = new OpenJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(true);
return jpaVendorAdapter;
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
final JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
}
package de.thm.arsnova.connector.services;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import javax.sql.DataSource;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.XmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import de.thm.arsnova.connector.config.RepositoryTestConfig;
import de.thm.arsnova.connector.persistence.domain.Configuration;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( classes = {RepositoryTestConfig.class} )
public class ConfigurationServiceTest {
@Autowired
private ConfigurationService configurationService;
@Autowired
private DataSource dataSource;
@Before
public void initDatabase() {
try {
final Connection con = dataSource.getConnection();
final IDatabaseConnection connection = new DatabaseConnection(con);
DatabaseOperation.CLEAN_INSERT.execute(connection, getDataSet());
} catch (final Exception e) {
e.printStackTrace();
}
}
@After
public void cleanupDatabase() {
}
private IDataSet getDataSet() throws Exception {
final FileInputStream fis = new FileInputStream(new File(
"src/test/resources/dbunit/internaldb.xml"));
return new XmlDataSet(fis);
}
@Test
public void testShouldReturnConfiguration() {
final Configuration actual = configurationService.getConfigurationElement("key2");
assertEquals("value2", actual.getValue());