Since I am new to Spring and i have an issue with user service. I have admin panel and customer blog. When the Customer is logged into browser, the admin has been changed the status to Active from InActive in Table of Customer. But the user session is active. So that he can able to do process after the status is changed.
I need one common method that should be in common place. This method should be access the table and validate the user per every request. I have one controller and that should invoke the common method. Because I cannot edit code to every class. In JSP & Servlet I have handled this using doFilter. How to achieve this in Spring..
AppInitializer.java
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(getMultipartConfigElement());
}
private MultipartConfigElement getMultipartConfigElement() {
MultipartConfigElement multipartConfigElement = new MultipartConfigElement( LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
return multipartConfigElement;
}
private static final String LOCATION = "C:/temp/"; // Temporary location where files will be stored
private static final long MAX_FILE_SIZE = 5242880; // 5MB : Max file size.
// Beyond that size spring will throw exception.
private static final long MAX_REQUEST_SIZE = 20971520; // 20MB : Total request size containing Multi part.
private static final int FILE_SIZE_THRESHOLD = 0;
}
AppConfig.java
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(getMultipartConfigElement());
}
private MultipartConfigElement getMultipartConfigElement() {
MultipartConfigElement multipartConfigElement = new MultipartConfigElement( LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
return multipartConfigElement;
}
private static final String LOCATION = "C:/temp/"; // Temporary location where files will be stored
private static final long MAX_FILE_SIZE = 5242880; // 5MB : Max file size.
// Beyond that size spring will throw exception.
private static final long MAX_REQUEST_SIZE = 20971520; // 20MB : Total request size containing Multi part.
private static final int FILE_SIZE_THRESHOLD = 0;
}
HibernateConfiguration.java
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
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.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.ppts.configuration" })
#PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.ppts.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
AppController.java
package com.sample.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import com.sample.handler.FileHandler;
import com.sample.model.Address;
import com.sample.model.Employee;
import com.sample.model.EmployeeDocument;
import com.sample.model.EmployeeSalary;
import com.sample.model.FileBucket;
import com.sample.model.User;
import com.sample.model.UserProfile;
import com.sample.service.EmployeeDocumentService;
import com.sample.service.EmployeeSalaryService;
import com.sample.service.EmployeeService;
import com.sample.service.UserProfileService;
import com.sample.service.UserService;
import com.sample.validators.FileValidator;
#Controller
#RequestMapping("/")
#SessionAttributes("roles")
public class AppController {
#Autowired
UserService userService;
#Autowired
EmployeeService employeeService;
#Autowired
EmployeeSalaryService employeeSalaryService;
#Autowired
UserProfileService userProfileService;
#Autowired
EmployeeDocumentService employeeDocumentService;
#Autowired
FileValidator fileValidator;
#InitBinder("fileBucket")
protected void initBinderFileBucket(WebDataBinder binder) {
binder.setValidator(fileValidator);
}
#Autowired
MessageSource messageSource;
#Autowired
PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices;
#Autowired
AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET)
public String adminPage(ModelMap model) {
model.addAttribute("home",true);
model.addAttribute("loggedinuser", getPrincipal());
return "home";
}
#RequestMapping(value = { "/userList" }, method = RequestMethod.GET)
public String listUsers(ModelMap model) {
List<User> users = userService.findAllUsers();
model.addAttribute("users", users);
model.addAttribute("loggedinuser", getPrincipal());
return "userslist";
}
#RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
public String newUser(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", false);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}
#RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(#Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registration";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registration";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
return "registrationsuccess";
}
#RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.GET)
public String editUser(#PathVariable String ssoId, ModelMap model) {
User user = userService.findBySSO(ssoId);
model.addAttribute("user", user);
model.addAttribute("edit", true);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}
#RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.POST)
public String updateUser(#Valid User user, BindingResult result,
ModelMap model, #PathVariable String ssoId) {
if (result.hasErrors()) {
return "registration";
}
userService.updateUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " updated successfully");
model.addAttribute("loggedinuser", getPrincipal());
return "registrationsuccess";
}
//Update User and Employee By Id
#RequestMapping(value = { "/getUserById" }, method = RequestMethod.GET)
public String getUserSSOId(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", true);
model.addAttribute("loggedinuser", getPrincipal());
return "userview";
}
#RequestMapping(value = { "/updateByUserId" }, method = RequestMethod.GET)
public String getByUserId( #ModelAttribute User userDetails,ModelMap model,BindingResult result) {
User user =userService.findBySSO(userDetails.getSsoId());
if(user!=null){
model.addAttribute("user", user);
model.addAttribute("edit", true);
model.addAttribute("loggedinuser", getPrincipal());
return "registration";
}else{
FieldError referenceIdError =new FieldError("user","ssoId",messageSource.getMessage("non.empty.userid.notexist", new String[]{userDetails.getSsoId()}, Locale.getDefault()));
result.addError(referenceIdError);
model.addAttribute("loggedinuser", getPrincipal());
return "userview";
}
}
#RequestMapping(value = { "/updateByUserId" }, method = RequestMethod.POST)
public String updateUserById(#Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registration";
}
userService.updateUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " updated successfully");
model.addAttribute("loggedinuser", getPrincipal());
return "registrationsuccess";
}
#RequestMapping(value = { "/deleteByUserId" }, method = RequestMethod.GET)
public String deleteUserById(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("delete", true);
model.addAttribute("loggedinuser", getPrincipal());
return "userview";
}
#RequestMapping(value = { "/deleteUserById" }, method = RequestMethod.GET)
public String deleteByuserId( #ModelAttribute User userDetails,ModelMap model,BindingResult result) {
User user=userService.findBySSO(userDetails.getSsoId());
if(user!=null){
userService.deleteUserBySSO(userDetails.getSsoId());
model.addAttribute("loggedinuser", getPrincipal());
model.addAttribute("employeeSuccess", "Employee " + user.getFirstName() + " deleted successfully");
return "registrationsuccess";
}else{
FieldError referenceIdError =new FieldError("employee","employeeReferenceId",messageSource.getMessage("non.empty.userid.notexist", new String[]{userDetails.getSsoId()}, Locale.getDefault()));
model.addAttribute("loggedinuser", getPrincipal());
result.addError(referenceIdError);
return "userview";
}
}
}
You can make create a class implementing Spring's HandlerInterceptor interface. Its preHandle method will be called for every request before request is processed by the Controller method.
Since you just want to process validation check for each request before it is handled, you can create a class extending the HandlerInterceptorAdapter class which provides convenient defaults for all methods in the HandlerInterceptor interface.
You only need to provide implementation as per your business rule for the following method
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
Sample code below
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class TransactionInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// Your business logic goes here
// return true or false depending on whether you want the controller to handle the request or terminate request processing.
}
}
You would need to register the interceptor in Spring Config as below
#EnableWebMvc
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
.....
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new YourNewInterceptor());
}
.....
}
You can do that also in Filter. You just have to annotate it with #Component and voila. It becomes a Spring bean. Like this:
#Component
public class UserFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
User user = (User)request.getAttribute("user");
// Do whatever you want with your user
}
#Override
public void destroy() {
}
}
Related
I am new in Java Spring Security and have an issue with Java Spring Security.
I have the problem that despite of using authorities and WebSecurityConfigurerAdapter
in Java Spring, users not having certain authorities can still go e.g. to /trainingsplan/**.
Concrete problem: When I am logged in as a user with only the authority "Constants.TRAINER", why am I able to access the url in the server /trainingsplan/all? This user is able to get all the training plans despite of not having the ADMIN authority :/
Do you see a mistake?
My implementation in UserPrincipalDetailsService:
package auth;
import entity.User;
import entity.UserPrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import repository.UserRepository;
import role.AuthorizationService;
import java.sql.SQLException;
import java.util.List;
#Component
#Service
public class UserPrincipalDetailsService implements UserDetailsService {
private UserRepository userRepository;
#Autowired
private ApplicationContext appContext;
private AuthorizationService authService;
// todo: autowire authservice here
#Lazy
#Autowired
private PasswordEncoder encoder;
public UserPrincipalDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
this.authService = new AuthorizationService(appContext);
}
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(s);
// String encodedPassword = encoder.encode(user.getPassword());
//user.setPassword(encodedPassword);
//user.setPassword(Bcrypter.getInstance().encode(user.getPassword()));
// encoder.encode(user.getPassword());
try {
List<String> roles = this.authService.getRolesToString(user.getId());
UserPrincipal userPrincipal = new UserPrincipal(user, roles.toArray(new String[0]));
return userPrincipal;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
My implementation in UserPrincipal:
package entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import role.Role;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class UserPrincipal implements UserDetails {
private String[] roles;
private User user;
public UserPrincipal(User user, String[] rolesString) {
this.user = user;
this.roles = rolesString;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
List<String> listRoles =
new ArrayList<String>(Arrays.asList(this.roles));
listRoles.forEach(p -> {
GrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
});
/**
// Extract list of permissions (name)
this.user.getPermissionList().forEach(p -> {
GrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
});
// Extract list of roles (ROLE_name)
this.user.getRoleList().forEach(r -> {
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + r);
authorities.add(authority);
});
*/
return authorities;
}
#Override
public String getPassword() {
return this.user.getPassword();
}
#Override
public String getUsername() {
return this.user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true; //this.user.getActive() == 1;
}
}
My implementation in the SecurityConfiguration:
package auth;
import org.springframework.context.ApplicationContext;
import repository.IUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
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.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;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import repository.UserRepository;
import util.Constants;
import java.util.Arrays;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final ApplicationContext context;
private UserPrincipalDetailsService userPrincipalDetailsService;
private UserRepository userRepository;
#Lazy
#Autowired
private PasswordEncoder encoder;
public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService, UserRepository userRepository, ApplicationContext applicationContext) {
this.userPrincipalDetailsService = userPrincipalDetailsService;
this.userRepository = userRepository;
this.context = applicationContext;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.addFilter(new JwtAuthenticationFilter(authenticationManager(), encoder, context))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), this.userRepository, context))
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers(HttpMethod.POST,"/admin/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/admin/**").permitAll()
.antMatchers(HttpMethod.PUT,"/admin/**").hasAnyAuthority(Constants.ADMIN, Constants.TRAINER)
.antMatchers(HttpMethod.GET,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN, Constants.CUSTOMER)
.antMatchers(HttpMethod.POST,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/customer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/customer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/customer/**").hasAuthority(Constants.ADMIN)
.and().
httpBasic().and().csrf().disable();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.addAllowedOriginPattern("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);
return daoAuthenticationProvider;
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I can ensure you that the authorities in the UserPrincipal are correct (in my example "TRAINER").
If there is something missing, please tell me.
I would be really thankful if someone could help me.
the above things..................
The following code is my soap web service with CRUD operations:
UserService.java
package com.gpcoder.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
#WebService
#SOAPBinding(style = SOAPBinding.Style.RPC)
public interface UserService {
#WebMethod
int insert(User user);
#WebMethod
boolean update(User user);
#WebMethod
boolean delete(int id);
#WebMethod
User get(int id);
#WebMethod
User[] getAll();
}
UserServiceImpl.java
package com.gpcoder.ws;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
#WebService(endpointInterface = "com.gpcoder.ws.UserService")
public class UserServiceImpl implements UserService {
private static final Map<Integer, User> USERS = new HashMap<>();
#Override
public int insert(User user) {
Integer id = generateUniqueId();
user.setId(id);
USERS.put(id, user);
return id;
}
private int generateUniqueId() {
return USERS.keySet().stream().max((x1, x2) -> x1 - x2).orElse(0) + 1;
}
#Override
public boolean update(User user) {
return USERS.put(user.getId(), user) != null;
}
#Override
public boolean delete(int id) {
return USERS.remove(id) != null;
}
#Override
public User get(int id) {
return USERS.getOrDefault(id, new User());
}
#Override
public User[] getAll() {
return USERS.values().toArray(new User[0]);
}
}
SoapPublisher.java
package com.gpcoder.ws;
import javax.xml.ws.Endpoint;
public class SoapPublisher {
public static final String WS_URL = "http://localhost:8080/ws/users";
public static void main(String[] args) {
Endpoint.publish(WS_URL, new UserServiceImpl());
System.out.println("Server is published!");
}
}
I would like to use the feign-soap library to call these soap API. I tried to implement it following the feign-soap document. Here is my client-side code:
pom.xml
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-soap -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-soap</artifactId>
<version>10.2.3</version>
</dependency>
UserService.java
import java.util.ArrayList;
import java.util.List;
import com.gpcoder.model.User;
import feign.Headers;
import feign.RequestLine;
#Headers({ "Content-Type: text/xml" })
public interface UserService {
#RequestLine("POST /get")
#Headers({ "SOAPAction: get" })
String getUser(int id);
#RequestLine("POST /insert")
#Headers({ "SOAPAction: insert" })
String createUser(User user);
#RequestLine("POST /update")
#Headers({ "SOAPAction: update" })
String updateUser(User user);
#RequestLine("POST /delete")
#Headers({ "SOAPAction: delete" })
String deleteUser(int id);
default List<String> getUsers(int... ids) {
List<String> orders = new ArrayList<>();
for (int id : ids) {
orders.add(this.getUser(id));
}
return orders;
}
}
FeignClientCreator.java
import feign.Feign;
import feign.jaxb.JAXBContextFactory;
import feign.soap.SOAPDecoder;
import feign.soap.SOAPEncoder;
import feign.soap.SOAPErrorDecoder;
public class FeignClientCreator {
public static final String BASE_URL = "http://localhost:8080/ws/users";
public static <T> T getService(Class<T> clazz) {
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
return Feign.builder()
.encoder(new SOAPEncoder(jaxbFactory))
.decoder(new SOAPDecoder(jaxbFactory))
.errorDecoder(new SOAPErrorDecoder())
.target(clazz, BASE_URL);
}
}
FeignClientExample.java
import java.io.IOException;
import com.gpcoder.helper.FeignClientCreator;
import com.gpcoder.model.User;
import com.gpcoder.service.UserService;
public class FeignClientExample {
private static UserService userService;
public static void main(String[] args) throws IOException {
userService = FeignClientCreator.getService(UserService.class);
createUser();
}
private static void createUser() throws IOException {
User user1 = new User();
user1.setId(1);
user1.setUsername("gpcoder.com");
System.out.println("createUser1: " + userService.createUser(user1));
}
}
I don't know where is my code wrong. When I run my program, it show error log:
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Cannot find dispatch method for {}user
at feign.soap.SOAPErrorDecoder.decode(SOAPErrorDecoder.java:68)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.sun.proxy.$Proxy3.createUser(Unknown Source)
at com.gpcoder.FeignClientExample.createUser(FeignClientExample.java:32)
at com.gpcoder.FeignClientExample.main(FeignClientExample.java:16)
Does anyone already worked with this library or have some documents about it please give me some information?
I dont seem to understand what is wrong with my code. I'm trying to login using Springboot security, everything seems correct and I can see my username and password on console. Can anyone tell me what i'm getting wrong?
Here's my SecSecurityConfig class
package com.scanapp.config;
import com.scanapp.repositories.RoleRepository;
import com.scanapp.services.UserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import
org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RoleRepository roleRepository;
#Autowired
#Qualifier("myuserdet")
UserDetailsService userDetailsService;
protected void init(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("I'm here");
auth.authenticationProvider(authProvider());
}
#Bean
public DaoAuthenticationProvider authProvider() {
System.out.println("got here");
DaoAuthenticationProvider authProvider = new
DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new CustomPassword();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources**").permitAll()
.anyRequest().permitAll()
.and().formLogin().loginPage("/login").successForwardUrl("/index").defaultSuccessUrl("/index",true).failureUrl("/login?error").permitAll()
.and()
.csrf().disable();
System.out.println("got here too");
}
}
UserServiceDetails.java
package com.scanapp.services;
import com.drew.metadata.StringValue;
import com.scanapp.config.MyUserPrincipal;
import com.scanapp.config.SecSecurityConfig;
import com.scanapp.models.User;
import com.scanapp.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Objects;
#Qualifier("myuserdet")
#Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByEmail(username);
if (Objects.nonNull(user)) {
MyUserPrincipal principal = new MyUserPrincipal(user);
System.out.println(String.valueOf(principal));
System.out.println("User Found");
System.out.println(principal.getPassword());
System.out.println(principal.getUsername());
return principal;
}else {
throw new BadCredentialsException("User Not found");
}
}
}
MyUserPrincipal.java
package com.scanapp.config;
import com.scanapp.models.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class MyUserPrincipal implements UserDetails {
private User user;
public MyUserPrincipal(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
#Override
public String getPassword()
{
return user.getPassword();
}
#Override
public String getUsername()
{
return user.getEmail();
}
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
#Override
public boolean isEnabled() {
return false;
}
}
CustomPassword.java
package com.scanapp.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class CustomPassword extends BCryptPasswordEncoder {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public String encode(CharSequence rawPassword) {
return super.encode(rawPassword);
}
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
System.out.println("paasword etered {}" + rawPassword);
return super.matches(rawPassword, encodedPassword);
}
}
Try to remove this block from the configuration. In theory Spring creates all of these beans behind the scenes (picking up your passwordEncoder and UserDetailsService automatically).
#Autowired
#Qualifier("myuserdet")
UserDetailsService userDetailsService;
protected void init(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("I'm here");
auth.authenticationProvider(authProvider());
}
#Bean
public DaoAuthenticationProvider authProvider() {
System.out.println("got here");
DaoAuthenticationProvider authProvider = new
DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
If it doesn't work try to rename your UserDetailsService (although that's a long shot).
You have a lot of noise in your code.
1.You defined CustomPassword which just extends BCryptPasswordEncoder. I suggest to return
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
2. You defined another User model which does nothing and has null list of granted authorities. It is odd, because it should fail if the list of authorities is null. Please return import
org.springframework.security.core.userdetails.User;
//..
return new User(userName, encodedPassword, Collections.singletonList(new SimpleGrantedAuthority("USER")
3.It is better to use another names for your beans, not the spring ones. please rename UserDetailsService to CustomUserDetailsService and don't use qualifiers in your configuration.
4.Please make sure that when you save the passwords in your database, they are hashed with BCryptPasswordEncoder.
OK. Another idea:
Based on the docs this method shouldn't return null:
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
return AuthorityUtils.NO_AUTHORITIES; instead.
In theory it could raise a NullpointerException during the authentication AFTER your UserDetailsService created the principal. And if there is a general catch (Exception e) somewhere there then it will be simply embedded into an AuthenticationException.
--- Edit
OUCH!
You should also change the return value to true in the last four method in the MyUserPrincipal class:
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
Your princapal was always disabled and expired and all. Of course it was not allowed to log in ! :)
I am using latest version of Spring Boot and I am trying to setup StatelessAuthenticaion. So far the tutorials I've been reading are very vague and I am not sure what I am doing wrong. The tutorials I am using is...
http://technicalrex.com/2015/02/20/stateless-authentication-with-spring-security-and-jwt/
The problem with my setup is that it seems everything is running correctly except for the fact that TokenAuthenticationService::addAuthentication is never called so my token is never set and therefore it returns null when the TokenAuthenticationService::getAuthentication is called and therefore returns a 401 even when I successfully logged in (Because addAuthentication is never called to set the token in the header). I am trying to figure a way to add TokenAuthenticationService::addAuthentication but I find it quite difficult.
In the tutorial he adds something similar to WebSecurityConfig::UserDetailsService.userService into auth.userDetailsService().. The only problem I am getting with that is when I do so, it throws a CastingErrorException. It only works when I utilize UserDetailsService customUserDetailsService instead...
WebSecurityConfig
package app.config;
import app.repo.User.CustomUserDetailsService;
import app.security.RESTAuthenticationEntryPoint;
import app.security.RESTAuthenticationFailureHandler;
import app.security.RESTAuthenticationSuccessHandler;
import app.security.TokenAuthenticationService;
import app.security.filters.StatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.sql.DataSource;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
#Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static PasswordEncoder encoder;
private final TokenAuthenticationService tokenAuthenticationService;
private final CustomUserDetailsService userService;
#Autowired
private UserDetailsService customUserDetailsService;
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
public WebSecurityConfig() {
this.userService = new CustomUserDetailsService();
tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets", userService);
}
#Autowired
public void configureAuth(AuthenticationManagerBuilder auth,DataSource dataSource) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").authenticated();
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().defaultSuccessUrl("/").successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler);
//This is ho
http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Bean
#Override
public CustomUserDetailsService userDetailsService() {
return userService;
}
#Bean
public TokenAuthenticationService tokenAuthenticationService() {
return tokenAuthenticationService;
}
}
The TokenAuthenticationService successfully calls the getAuthentication method but in the tutorials I read, there is no proper explanation on how addAuthentication is called
TokenAuthenticationService
package app.security;
import app.repo.User.CustomUserDetailsService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TokenAuthenticationService {
private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN";
private final TokenHandler tokenHandler;
//This is called in my WebSecurityConfig() constructor
public TokenAuthenticationService(String secret, CustomUserDetailsService userService) {
tokenHandler = new TokenHandler(secret, userService);
}
public void addAuthentication(HttpServletResponse response, UserAuthentication authentication) {
final UserDetails user = authentication.getDetails();
response.addHeader(AUTH_HEADER_NAME, tokenHandler.createTokenForUser(user));
}
public Authentication getAuthentication(HttpServletRequest request) {
final String token = request.getHeader(AUTH_HEADER_NAME);
if (token != null) {
final UserDetails user = tokenHandler.parseUserFromToken(token);
if (user != null) {
return new UserAuthentication(user);
}
}
return null;
}
}
TokenHandler
package app.security;
import app.repo.User.CustomUserDetailsService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
public final class TokenHandler {
private final String secret;
private final CustomUserDetailsService userService;
public TokenHandler(String secret, CustomUserDetailsService userService) {
this.secret = secret;
this.userService = userService;
}
public UserDetails parseUserFromToken(String token) {
String username = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
return userService.loadUserByUsername(username);
}
public String createTokenForUser(UserDetails user) {
return Jwts.builder()
.setSubject(user.getUsername())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
}
In my WebServiceConfig. I add the following
http.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
Which calls on the following class as a filter. It gets the Authentication, but there is No where where it actually adds it.
StatelessAuthenticationFilter
package app.security.filters;
import app.security.TokenAuthenticationService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* Created by anthonygordon on 11/17/15.
*/
public class StatelessAuthenticationFilter extends GenericFilterBean {
private final TokenAuthenticationService authenticationService;
public StatelessAuthenticationFilter(TokenAuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
Authentication authentication = authenticationService.getAuthentication(httpRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication(null);
}
}
The following class is what gets passed in the TokenAuthenticationService::addAuthentication
UserAuthentication
package app.security;
import app.repo.User.User;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class UserAuthentication implements Authentication {
private final UserDetails user;
private boolean authenticated = true;
public UserAuthentication(UserDetails user) {
this.user = user;
}
#Override
public String getName() {
return user.getUsername();
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
#Override
public Object getCredentials() {
return user.getPassword();
}
#Override
public UserDetails getDetails() {
return user;
}
#Override
public Object getPrincipal() {
return user.getUsername();
}
#Override
public boolean isAuthenticated() {
return authenticated;
}
#Override
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
}
Thats it...
My Solution (But Need Help)...
My solution was to set the TokenAuthenticationService::addAuthentication method in my success handler... The only problem with that is the tutorial added the class TokenAuthenticationService to the WebServiceConfig class. And thats the only place its accessible. If there is a way I can obtain it in my successHandler, I might be able to set the token.
package app.security;
import app.controllers.Requests.TriviaResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by anthonygordon on 11/12/15.
*/
#Component
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
TriviaResponse tresponse = new TriviaResponse();
tresponse.setMessage("You have successfully logged in");
String json = ow.writeValueAsString(tresponse);
response.getWriter().write(json);
clearAuthenticationAttributes(request);
}
}
You have to call TokenAuthenticationService.addAuthentication() yourself when a user supplies their login credentials the first time.
The tutorial calls addAuthentication() in GoogleAuthorizationResponseServlet after a user successfully logs in using their Google account. Here's the relevant code:
private String establishUserAndLogin(HttpServletResponse response, String email) {
// Find user, create if necessary
User user;
try {
user = userService.loadUserByUsername(email);
} catch (UsernameNotFoundException e) {
user = new User(email, UUID.randomUUID().toString(), Sets.<GrantedAuthority>newHashSet());
userService.addUser(user);
}
// Login that user
UserAuthentication authentication = new UserAuthentication(user);
return tokenAuthenticationService.addAuthentication(response, authentication);
}
If you already have an authentication success handler, then I think you're on the right track that you need to call TokenAuthenticationService.addAuthentication() from there. Inject the tokenAuthenticationService bean into your handler and then start using it. If your success handler doesn't end up being a Spring bean then you can explicitly look tokenAuthenticationService up by calling WebApplicationContextUtils.getRequiredWebApplicationContext.getBean(TokenAuthenticationService.class).
There is also an issue in the tutorial's GitHub repo that will address the confusion between the initial login supplied by the user and the stateless authentication happening on all subsequent requests.
you can define a StatelessLoginFilter like below
.addFilterBefore(
new StatelessLoginFilter("/api/signin",
tokenAuthenticationService, userDetailsService,
authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
and write the class like this
class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter {
private final TokenAuthenticationService tokenAuthenticationService;
private final UserDetailsService userDetailsService;
protected StatelessLoginFilter(String urlMapping,
TokenAuthenticationService tokenAuthenticationService,
UserDetailsService userDetailsService,
AuthenticationManager authManager) {
super(new AntPathRequestMatcher(urlMapping));
this.userDetailsService = userDetailsService;
this.tokenAuthenticationService = tokenAuthenticationService;
setAuthenticationManager(authManager);
}
#Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain,
Authentication authentication) throws IOException, ServletException {
final User authenticatedUser = userDetailsService
.loadUserByUsername(authentication.getName());
final UserAuthentication userAuthentication = new UserAuthentication(
authenticatedUser);
tokenAuthenticationService.addAuthentication(response,
userAuthentication);
SecurityContextHolder.getContext()
.setAuthentication(userAuthentication);
}
}
I try to build web application on Java with Spring-MVC and Spring-Security.
In one module where I need get information from database, I can't get SessionFactory.
Form more information, here is my java config and other files source codes:
WebAppConfig.java:
package com.sprsec.init;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.*;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.sprsec")
#PropertySource("classpath:application.properties")
#ImportResource("classpath:spring-security.xml")
public class WebAppConfig extends WebMvcConfigurerAdapter {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
private static final String PROPERTY_NAME_POOL_SIZE = "hibernate.pool_size";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
#Bean
public SessionFactory getSessioFactory(){
return sessionFactory().getObject();
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_POOL_SIZE, env.getRequiredProperty(PROPERTY_NAME_POOL_SIZE));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean(name = "messageSource")
public AbstractMessageSource getMesageSource(){
return new DatabaseMessageSource(sessionFactory().getObject());
}
#Bean
public HandlerInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
//resolver.setSuffix(".xhtml");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(StringUtils.parseLocaleString("en"));
return cookieLocaleResolver;
}
}
UserDAOImpl.java:
package com.sprsec.dao;
import com.sprsec.model.User;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
#Repository
public class UserDAOImpl implements UserDAO {
#Autowired
private SessionFactory sessionFactory;
private Session getSession(){
return sessionFactory.getCurrentSession();
}
public User getUser(String login) {
List<User> userList = new ArrayList<User>();
Query query = getSession().createQuery("from User u where u.login = :login");
query.setParameter("login", login);
System.out.println(query.getQueryString());
userList = query.list();
if (userList.size() > 0)
return userList.get(0);
else
return null;
}
public User getUserByLoginAndPassword(String login, String password){
Query query = getSession().createQuery("from User u where u.login = :login and u.password = :password");
query.setParameter("login", login);
query.setParameter("password", password);
User user = (User) query.uniqueResult();
return user;
}
}
Here, in UserDAOImpl.java, I retrieve an Exception. SessionFactory is null.
I mind what problem is in my WebAppConfig class because in DatabaseMessageSource.java I retrieve the same exception and I'l add this class in config and over constructor put SessionFactory. I do not want to add there every class that needs this dependency.
Error Message:
Caused by: java.lang.NullPointerException
at com.sprsec.init.DatabaseMessageSource.openSession(DatabaseMessageSource.java:95)
at com.sprsec.init.DatabaseMessageSource.getSQLDictionary(DatabaseMessageSource.java:104)
at com.sprsec.init.DatabaseMessageSource.loadTexts(DatabaseMessageSource.java:114)
at com.sprsec.init.DatabaseMessageSource.refreshProperties(DatabaseMessageSource.java:90)
at com.sprsec.init.DatabaseMessageSource.reload(DatabaseMessageSource.java:132)
at com.sprsec.init.DatabaseMessageSource.<init>(DatabaseMessageSource.java:35)
at com.sprsec.init.WebAppConfig.getMesageSource(WebAppConfig.java:90)
at com.sprsec.init.WebAppConfig$$EnhancerByCGLIB$$f4b941bb.CGLIB$getMesageSource$3(<generated>)
at com.sprsec.init.WebAppConfig$$EnhancerByCGLIB$$f4b941bb$$FastClassByCGLIB$$c1655200.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:286)
at com.sprsec.init.WebAppConfig$$EnhancerByCGLIB$$f4b941bb.getMesageSource(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
... 57 more
DatabaseMessageSource.java:
public class DatabaseMessageSource extends AbstractMessageSource implements MessageSource {
private final Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
#Autowired
private SessionFactory sessionFactory;
public DatabaseMessageSource() {
super();
//this.sessionFactory = sessionFactory;
this.setUseCodeAsDefaultMessage(true);
reload();
setParentMessageSource(this);
}
/**
* {#inheritDoc}
*/
#Override
protected String resolveCodeWithoutArguments(String code, Locale locale) {
return getText(code, locale);
}
/**
* {#inheritDoc}
*/
#Override
protected MessageFormat resolveCode(String code, Locale locale) {
String msg = getText(code, locale);
MessageFormat result = createMessageFormat(msg, locale);
return result;
}
/**
* #param code
* #param locale
* #return
*/
private String getText(String code, Locale locale) {
Map<String, String> localizedText = properties.get(locale.getLanguage());
System.out.println("===================================================");
System.out.println("requested code: "+code+" Result: "+localizedText.get(code));
System.out.println("===================================================");
String textForCurrentLanguage = null;
if (localizedText != null) {
textForCurrentLanguage = localizedText.get(code);
if (textForCurrentLanguage == null) {
saveKeyword(code);
reload();
return "__"+code;
}else if (textForCurrentLanguage.equals("")){
return "__"+code;
} else {
return textForCurrentLanguage;
}
} else {
return "__"+code;
}
}
/**
* #return properties which keeps localized text
*/
private Map<String, Map<String, String>> refreshProperties() {
properties.clear();
properties.putAll(loadTexts());
return properties;
}
public Session openSession(){
return sessionFactory.openSession();
}
private void saveKeyword(final String key){
Query query = openSession().createSQLQuery("insert into b_dictionary (keyword,lang_ru,lang_lv,lang_en) values ('"+key+"','','','')");
query.executeUpdate();
}
private Iterator getSQLDictionary(){
Query query = openSession().createSQLQuery("select m.keyword, m.lang_ru, m.lang_lv, m.lang_en from b_dictionary as m");
return query.list().iterator();
}
protected Map<String, Map<String, String>> loadTexts() {
Map<String, Map<String, String>> myProp = new HashMap<String, Map<String, String>>();
Map<String, String> dataRU = new HashMap<String, String>();
Map<String, String> dataLV = new HashMap<String, String>();
Map<String, String> dataEN = new HashMap<String, String>();
Iterator result = getSQLDictionary();
while( result.hasNext() ){
Object[] row = (Object[]) result.next();
String code = row[0].toString();
dataRU.put(code,row[1].toString());
dataLV.put(code,row[2].toString());
dataEN.put(code,row[3].toString());
}
myProp.put("ru", dataRU);
myProp.put("lv", dataLV);
myProp.put("en", dataEN);
return myProp;
}
/**
* Reload all codes.
*/
public void reload() {
refreshProperties();
}
}
Your problem is here:
new DatabaseMessageSource(sessionFactory().getObject());
Spring can only autowire beans that it manages; if you call new to create a bean yourself, #Autowired fields don't get filled in (and methods like #PostConstruct aren't called). The field should get filled in after it gets returned by the #Bean method, but if you need to access it in the bean's constructor, you'll have to pass it in as a parameter. The preferred solution is to move the code that relies on the #Autowired setup into a method annotated with #PostConstruct.
Try AnnotationSessionFactoryBean instead of LocalSessionFactoryBean
LocalSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();