diff --git a/spring-security-custom-permission/WebContent/META-INF/MANIFEST.MF b/spring-security-custom-permission/WebContent/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..254272e1c0
--- /dev/null
+++ b/spring-security-custom-permission/WebContent/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/spring-security-custom-permission/derby.log b/spring-security-custom-permission/derby.log
new file mode 100644
index 0000000000..3c0968fa9c
--- /dev/null
+++ b/spring-security-custom-permission/derby.log
@@ -0,0 +1,13 @@
+----------------------------------------------------------------
+Wed Oct 05 21:59:32 EEST 2016:
+Booting Derby version The Apache Software Foundation - Apache Derby - 10.12.1.1 - (1704137): instance a816c00e-0157-9637-0b63-000000c038f0
+on database directory memory:C:\Users\lore\Documents\workspace-articles\spring-security-custom-permission\spring_custom_user_service with class loader sun.misc.Launcher$AppClassLoader@6433a2
+Loaded from file:/C:/Users/lore/.m2/repository/org/apache/derby/derby/10.12.1.1/derby-10.12.1.1.jar
+java.vendor=Oracle Corporation
+java.runtime.version=1.8.0_77-b03
+user.dir=C:\Users\lore\Documents\workspace-articles\spring-security-custom-permission
+os.name=Windows 7
+os.arch=x86
+os.version=6.1
+derby.system.home=null
+Database Class Loader started - derby.database.classpath=''
diff --git a/spring-security-custom-permission/pom.xml b/spring-security-custom-permission/pom.xml
index 6f460f1751..d036975107 100644
--- a/spring-security-custom-permission/pom.xml
+++ b/spring-security-custom-permission/pom.xml
@@ -86,6 +86,48 @@
+
+
+ org.springframework
+ spring-test
+ test
+
+
+
+ org.apache.derby
+ derby
+ 10.12.1.1
+
+
+ org.apache.derby
+ derbyclient
+ 10.12.1.1
+
+
+ org.apache.derby
+ derbynet
+ 10.12.1.1
+
+
+ org.apache.derby
+ derbytools
+ 10.12.1.1
+
+
+ taglibs
+ standard
+ 1.1.2
+
+
+ org.springframework.security
+ spring-security-taglibs
+ 4.1.3.RELEASE
+
+
+ javax.servlet.jsp.jstl
+ jstl-api
+ 1.2
+
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/config/PersistenceConfig.java b/spring-security-custom-permission/src/main/java/org/baeldung/config/PersistenceConfig.java
new file mode 100644
index 0000000000..cd7caa5fd1
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/config/PersistenceConfig.java
@@ -0,0 +1,87 @@
+package org.baeldung.config;
+
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+import javax.sql.DataSource;
+
+import org.baeldung.persistence.dao.MyUserRepository;
+import org.baeldung.persistence.dao.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+@PropertySource({ "classpath:persistence-derby.properties" })
+public class PersistenceConfig {
+
+ @Autowired
+ private Environment env;
+
+ public PersistenceConfig() {
+ super();
+ }
+
+ // beans
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean myEmf() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(dataSource());
+ em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ em.setJpaProperties(additionalProperties());
+
+ return em;
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
+ dataSource.setUrl(env.getProperty("jdbc.url"));
+ dataSource.setUsername(env.getProperty("jdbc.user"));
+ dataSource.setPassword(env.getProperty("jdbc.pass"));
+
+ return dataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager transactionManager(final EntityManagerFactory emf) {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(emf);
+ return transactionManager;
+ }
+
+ @Bean
+ public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+ return new PersistenceExceptionTranslationPostProcessor();
+ }
+
+ final Properties additionalProperties() {
+ final Properties hibernateProperties = new Properties();
+ hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache"));
+ hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache"));
+ // hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
+ return hibernateProperties;
+ }
+
+ @Bean
+ public UserRepository userRepository(){
+ return new MyUserRepository();
+ }
+}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java b/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java
index b365744bea..21b81741ee 100644
--- a/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java
@@ -1,14 +1,20 @@
package org.baeldung.config;
+import org.baeldung.persistence.dao.MyUserRepository;
+import org.baeldung.persistence.dao.UserRepository;
import org.baeldung.security.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@@ -40,4 +46,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
;
// @formatter:on
}
+
+ @Bean
+ public DaoAuthenticationProvider authenticationProvider() {
+ final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+ authProvider.setUserDetailsService(userDetailsService);
+ authProvider.setPasswordEncoder(encoder());
+ return authProvider;
+ }
+
+ @Bean
+ public PasswordEncoder encoder() {
+ return new BCryptPasswordEncoder(11);
+ }
}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/MyUserRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/MyUserRepository.java
new file mode 100644
index 0000000000..ee290a0c35
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/MyUserRepository.java
@@ -0,0 +1,146 @@
+package org.baeldung.persistence.dao;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+
+import org.baeldung.persistence.model.User;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class MyUserRepository implements UserRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Override
+ public List findAll() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List findAll(Sort sort) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List findAll(Iterable ids) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List save(Iterable entities) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void flush() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public S saveAndFlush(S entity) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void deleteInBatch(Iterable entities) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void deleteAllInBatch() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public User getOne(Long id) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Page findAll(Pageable arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public long count() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void delete(Long arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void delete(User arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void delete(Iterable extends User> arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void deleteAll() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean exists(Long arg0) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public User findOne(Long arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public S save(S user) {
+ entityManager.persist(user);
+ return user;
+ }
+
+ @Override
+ public User findByUsername(String username) {
+ Query query = entityManager.createQuery("from User where username=:username", User.class);
+ query.setParameter("username", username);
+ List result = query.getResultList();
+ if (result != null && result.size() > 0) {
+ return result.get(0);
+ } else
+ return null;
+ }
+
+ public void removeUserByUsername(String username) {
+ final Query query = entityManager.createQuery("delete from User where username=:username");
+ query.setParameter("username", username);
+ query.executeUpdate();
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java
index 679dd6c363..8b4e20d146 100644
--- a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java
@@ -6,5 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository {
User findByUsername(final String username);
+
+ void removeUserByUsername(String username);
}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java
index 112d502105..67f18c1398 100644
--- a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java
@@ -12,8 +12,10 @@ import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
+import javax.persistence.Table;
@Entity
+@Table(name="user_table")
public class User {
@Id
diff --git a/spring-security-custom-permission/src/main/resources/persistence-derby.properties b/spring-security-custom-permission/src/main/resources/persistence-derby.properties
new file mode 100644
index 0000000000..e808fdc288
--- /dev/null
+++ b/spring-security-custom-permission/src/main/resources/persistence-derby.properties
@@ -0,0 +1,12 @@
+# jdbc.X
+jdbc.driverClassName=org.apache.derby.jdbc.EmbeddedDriver
+jdbc.url=jdbc:derby:memory:spring_custom_user_service;create=true
+jdbc.user=tutorialuser
+jdbc.pass=tutorialpass
+
+# hibernate.X
+hibernate.dialect=org.hibernate.dialect.DerbyDialect
+hibernate.show_sql=false
+hibernate.hbm2ddl.auto=create
+hibernate.cache.use_second_level_cache=false
+hibernate.cache.use_query_cache=false
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/test/java/org/baeldung/web/CustomUserDetailsServiceTest.java b/spring-security-custom-permission/src/test/java/org/baeldung/web/CustomUserDetailsServiceTest.java
new file mode 100644
index 0000000000..390bd7c96c
--- /dev/null
+++ b/spring-security-custom-permission/src/test/java/org/baeldung/web/CustomUserDetailsServiceTest.java
@@ -0,0 +1,83 @@
+package org.baeldung.web;
+
+import org.baeldung.config.MvcConfig;
+import org.baeldung.config.PersistenceConfig;
+import org.baeldung.config.SecurityConfig;
+import org.baeldung.persistence.dao.UserRepository;
+import org.baeldung.persistence.model.User;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import static org.junit.Assert.*;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = { MvcConfig.class, SecurityConfig.class, PersistenceConfig.class })
+@WebAppConfiguration
+public class CustomUserDetailsServiceTest {
+
+ private static final Logger LOG = Logger.getLogger("CustomUserDetailsServiceTest");
+
+ public static final String USERNAME = "user";
+ public static final String PASSWORD = "pass";
+ public static final String USERNAME2 = "user2";
+
+ @Autowired
+ UserRepository myUserRepository;
+
+ @Autowired
+ AuthenticationProvider authenticationProvider;
+
+ @Test
+ public void givenExistingUser_whenAuthenticate_thenRetrieveFromDb() {
+ try {
+ User user = new User();
+ user.setUsername(USERNAME);
+ user.setPassword(PASSWORD);
+
+ myUserRepository.save(user);
+
+ UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(USERNAME, PASSWORD);
+ Authentication authentication = authenticationProvider.authenticate(auth);
+
+ assertEquals(authentication.getName(), USERNAME);
+
+ } catch (Exception exc) {
+ LOG.log(Level.SEVERE, "Error creating account");
+ } finally {
+ myUserRepository.removeUserByUsername(USERNAME);
+ }
+ }
+
+ @Test (expected = BadCredentialsException.class)
+ public void givenIncorrectUser_whenAuthenticate_thenBadCredentialsException() {
+ try {
+ User user = new User();
+ user.setUsername(USERNAME);
+ user.setPassword(PASSWORD);
+
+ try {
+ myUserRepository.save(user);
+ }
+ catch (Exception exc) {
+ LOG.log(Level.SEVERE, "Error creating account");
+ }
+
+ UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(USERNAME2, PASSWORD);
+ Authentication authentication = authenticationProvider.authenticate(auth);
+ }
+ finally {
+ myUserRepository.removeUserByUsername(USERNAME);
+ }
+ }
+
+}