I am using spring security 4 and mybatis as an orm to the database. For authentication I am using mobile number and a generated OTP(still left to implement). I am getting a null pointer error as the AuthenticationProvider class for some reason can not communicate with the database throught the ORM.
My security configuration class
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsServiceImpl userDetailsService = new UserDetailsServiceImpl();
auth.userDetailsService(userDetailsService);
//auth.inMemoryAuthentication().withUser("9822012345").password("password");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login*").permitAll()
.antMatchers("/**").access("hasRole('USER')")
.and().formLogin()
.and().csrf();
}
My interface for user class
public interface UserDao {
#Select("SELECT * FROM \"Users\" WHERE \"Email\" = '${Email}'")
#Results(value = {
#Result(property = "Email", column = "Email"),
#Result(property = "Name", column = "Name"),
#Result(property = "MobileNumber", column = "MobileNumber"),
#Result(property = "LoggedIn", column = "LoggedIn"),
#Result(property = "Balance", column = "Balance")
})
public User getUserByEmail(#Param("Email") String Email);
#Select("SELECT * FROM \"Users\" WHERE \"Name\" = '${Name}'")
#Results(value = {
#Result(property = "Email", column = "Email"),
#Result(property = "Name", column = "Name"),
#Result(property = "MobileNumber", column = "MobileNumber"),
#Result(property = "LoggedIn", column = "LoggedIn"),
#Result(property = "Balance", column = "Balance")
})
public User getUserByName(#Param("Name") String Name);
#Select("SELECT * FROM \"Users\" WHERE \"MobileNumber\" = '${MobileNumber}'")
#Results(value = {
#Result(property = "Email", column = "Email"),
#Result(property = "Name", column = "Name"),
#Result(property = "MobileNumber", column = "MobileNumber"),
#Result(property = "LoggedIn", column = "LoggedIn"),
#Result(property = "Balance", column = "Balance")
})
public User getUserByMobileNumber(#Param("MobileNumber") String mobileNumber);
}
My class which implements the interface
#Service
#Transactional
public class UserDaoImpl {
private UserDao userDao;
#Autowired
public void setUserDao(UserDao userDao) {
if(userDao != null) this.userDao = userDao;
}
public User getUserByEmail(String email) {
return userDao.getUserByEmail(email);
}
public User getUserByName(String email) {
return userDao.getUserByName(email);
}
public User getUserByMobileNumber(String mobileNumber) {
System.out.println("Comes in userdaoimpl.. " + mobileNumber);
User u = userDao.getUserByMobileNumber(mobileNumber);
if(u!=null) { return u; }
else {
System.out.println("User returned null. Maybe Database problem.");
return null;
}
}
}
And my user details service implementation
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.iz.zpservice.dao.impl.UserDaoImpl;
import com.iz.zpservice.model.User;
#Service
#Transactional
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
UserDaoImpl userDaoImpl = new UserDaoImpl();
public User getUserByMobileNumber(String mobileNumber) {
return userDaoImpl.getUserByMobileNumber(mobileNumber);
}
#Override
public UserDetails loadUserByUsername(String mobileNumber) throws UsernameNotFoundException {
System.out.println(mobileNumber + "The number provided.");
String otp = "password"; /* Add Otp method and
* initialize this
* object
*/
try {
User user = getUserByMobileNumber(mobileNumber);
System.out.println(user.getName() + "User has been fetched.");
} catch (UsernameNotFoundException u) {
throw new UsernameNotFoundException("No such number registered: " + mobileNumber);
}
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new org.springframework.security.core.userdetails.User(mobileNumber, otp,
true, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(mobileNumber));
}
public Collection<? extends GrantedAuthority> getAuthorities(String mobileNumber) {
List<GrantedAuthority> authList = null;
authList = new ArrayList<GrantedAuthority>();
SimpleGrantedAuthority sGA = new SimpleGrantedAuthority(new String("ROLE_USER"));
authList.add(sGA);
return authList;
}
}
And the stack trace
INFO: Server startup in 6346 ms
9822012345The number provided.
Comes in userdaoimpl.. 9822012345
Oct 08, 2015 4:44:53 PM org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter doFilter
SEVERE: An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:125)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:143)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at com.iz.zpservice.dao.impl.UserDaoImpl.getUserByMobileNumber(UserDaoImpl.java:30)
at com.iz.zpservice.service.UserDetailsServiceImpl.getUserByMobileNumber(UserDetailsServiceImpl.java:26)
at com.iz.zpservice.service.UserDetailsServiceImpl.loadUserByUsername(UserDetailsServiceImpl.java:38)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:114)
... 41 more
I had made a stupid mistake. I needed to add the UserDetailsServicesImpl object inside the class and Autowire it, instead I declared it inside the configure.. method.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsServiceImpl userDetailsService = new UserDetailsServiceImpl();
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
//auth.inMemoryAuthentication().withUser("9822012345").password("password");
}
Related
I recently wrote a spring boot project that uses spring security oauth2, the auth server is IdentityServer4 for some reason, I can successfully login and get username in my project but I cannot find any way to set user's authority/role.
request.isUserInRole always return false.
#PreAuthorize("hasRole('rolename')") always lead me to 403.
Where can I place some code to set the authorities?
The server has returned some user claims through userinfo endpoint, and my project received them, and I can even see it in the principle param of my controller.
This method always return 403
#ResponseBody
#RequestMapping("admin")
#PreAuthorize("hasRole('admin')")
public String admin(HttpServletRequest request){
return "welcome, you are admin!" + request.isUserInRole("ROLE_admin");
}
application.properties
spring.security.oauth2.client.provider.test.issuer-uri = http://localhost:5000
spring.security.oauth2.client.provider.test.user-name-attribute = name
spring.security.oauth2.client.registration.test.client-id = java
spring.security.oauth2.client.registration.test.client-secret = secret
spring.security.oauth2.client.registration.test.authorization-grant-type = authorization_code
spring.security.oauth2.client.registration.test.scope = openid profile
I print the claims
#ResponseBody
#RequestMapping()
public Object index(Principal user){
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken)user;
return token.getPrincipal().getAttributes();
}
and get the result show there is a claim named 'role'
{"key":"value","role":"admin","preferred_username":"bob"}
Anybody can help me and give me a solution please?
EDIT 1:
The reason is oauth2 client has removed the extracter, and I have to implement the userAuthoritiesMapper.
Finally I got this work by adding the following class:
#Configuration
public class AppConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login().userInfoEndpoint().userAuthoritiesMapper(this.userAuthoritiesMapper());
//.oidcUserService(this.oidcUserService());
super.configure(http);
}
private GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
if (OidcUserAuthority.class.isInstance(authority)) {
OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;
OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
if (userInfo.containsClaim("role")){
String roleName = "ROLE_" + userInfo.getClaimAsString("role");
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
} else if (OAuth2UserAuthority.class.isInstance(authority)) {
OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
if (userAttributes.containsKey("role")){
String roleName = "ROLE_" + (String)userAttributes.get("role");
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
}
});
return mappedAuthorities;
};
}
}
The framework changes so fast and the demos on the web is too old!
I spent a few hours and I find the solution. The problem is with spring oauth security, by default it obtain the user roles from the token using the key 'authorities'. So, I implemented a custom token converter.
The first you need is the custom user token converter, here is the class:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class CustomUserTokenConverter implements UserAuthenticationConverter {
private Collection<? extends GrantedAuthority> defaultAuthorities;
private UserDetailsService userDetailsService;
private final String AUTHORITIES = "role";
private final String USERNAME = "preferred_username";
private final String USER_IDENTIFIER = "sub";
public CustomUserTokenConverter() {
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
public void setDefaultAuthorities(String[] defaultAuthorities) {
this.defaultAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.arrayToCommaDelimitedString(defaultAuthorities));
}
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap();
response.put(USERNAME, authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
public Authentication extractAuthentication(Map<String, ?> map) {
if (map.containsKey(USER_IDENTIFIER)) {
Object principal = map.get(USER_IDENTIFIER);
Collection<? extends GrantedAuthority> authorities = this.getAuthorities(map);
if (this.userDetailsService != null) {
UserDetails user = this.userDetailsService.loadUserByUsername((String)map.get(USER_IDENTIFIER));
authorities = user.getAuthorities();
principal = user;
}
return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
} else {
return null;
}
}
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
if (!map.containsKey(AUTHORITIES)) {
return this.defaultAuthorities;
} else {
Object authorities = map.get(AUTHORITIES);
if (authorities instanceof String) {
return AuthorityUtils.commaSeparatedStringToAuthorityList((String)authorities);
} else if (authorities instanceof Collection) {
return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.collectionToCommaDelimitedString((Collection)authorities));
} else {
throw new IllegalArgumentException("Authorities must be either a String or a Collection");
}
}
}
}
The you need a custom token converter, here is:
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.stereotype.Component;
import java.util.Map;
#Component
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {
#Override
public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
OAuth2Authentication authentication = super.extractAuthentication(claims);
authentication.setDetails(claims);
return authentication;
}
}
And finally you ResourceServerConfiguration looks like this:
import hello.helper.CustomAccessTokenConverter;
import hello.helper.CustomUserTokenConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.anyRequest().access("hasAnyAuthority('Admin')");
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("arawaks");
}
#Bean
#Primary
public RemoteTokenServices tokenServices() {
final RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("resourceId");
tokenServices.setClientSecret("resource.secret");
tokenServices.setCheckTokenEndpointUrl("http://localhost:5001/connect/introspect");
tokenServices.setAccessTokenConverter(accessTokenConverter());
return tokenServices;
}
#Bean
public CustomAccessTokenConverter accessTokenConverter() {
final CustomAccessTokenConverter converter = new CustomAccessTokenConverter();
converter.setUserTokenConverter(new CustomUserTokenConverter());
return converter;
}
}
Apparently #wjsgzcn answer (EDIT 1) DOES NOT WORK for reasons below
If you print the attributes returned by the Oauth2UserAuthirty class you will soon notice the contents of the JSON data does not have the role key instead has an authorities key hence you need to use that key to iterate over the list of authorities (roles) to get the actual role name.
Hence the following lines of code will not work as there is no role key in the JSON data returned by the oauth2UserAuthority.getAttributes();
OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
if (userAttributes.containsKey("role")){
String roleName = "ROLE_" + (String)userAttributes.get("role");
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
So instead use the following to get the actual role from the getAttributes
if (userAttributes.containsKey("authorities")){
ObjectMapper objectMapper = new ObjectMapper();
ArrayList<Role> authorityList =
objectMapper.convertValue(userAttributes.get("authorities"), new
TypeReference<ArrayList<Role>>() {});
log.info("authList: {}", authorityList);
for(Role role: authorityList){
String roleName = "ROLE_" + role.getAuthority();
log.info("role: {}", roleName);
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
}
Where the Role is a pojo class like so
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Role {
#JsonProperty
private String authority;
}
That way you will be able to get the ROLE_ post prefix which is the actual role granted to the user after successfully authenticated to the Authorization server and the client is returned the LIST of granted authorities (roles).
Now the complete GrantedAuthoritesMapper look like the following:
private GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
if (OidcUserAuthority.class.isInstance(authority)) {
OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;
OidcIdToken idToken = oidcUserAuthority.getIdToken();
OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
// Map the claims found in idToken and/or userInfo
// to one or more GrantedAuthority's and add it to mappedAuthorities
if (userInfo.containsClaim("authorities")){
ObjectMapper objectMapper = new ObjectMapper();
ArrayList<Role> authorityList = objectMapper.convertValue(userInfo.getClaimAsMap("authorities"), new TypeReference<ArrayList<Role>>() {});
log.info("authList: {}", authorityList);
for(Role role: authorityList){
String roleName = "ROLE_" + role.getAuthority();
log.info("role: {}", roleName);
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
}
} else if (OAuth2UserAuthority.class.isInstance(authority)) {
OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;
Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
log.info("userAttributes: {}", userAttributes);
// Map the attributes found in userAttributes
// to one or more GrantedAuthority's and add it to mappedAuthorities
if (userAttributes.containsKey("authorities")){
ObjectMapper objectMapper = new ObjectMapper();
ArrayList<Role> authorityList = objectMapper.convertValue(userAttributes.get("authorities"), new TypeReference<ArrayList<Role>>() {});
log.info("authList: {}", authorityList);
for(Role role: authorityList){
String roleName = "ROLE_" + role.getAuthority();
log.info("role: {}", roleName);
mappedAuthorities.add(new SimpleGrantedAuthority(roleName));
}
}
}
});
log.info("The user authorities: {}", mappedAuthorities);
return mappedAuthorities;
};
}
Now you are able to use the userAuthorityMapper in your oauth2Login as follows
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.antMatchers("/clientPage/**").hasRole("CLIENT")
.anyRequest().authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.userAuthoritiesMapper(userAuthoritiesMapper());
}
I'm trying to populate the database with a hashed password and then log in to my application, by matching the data I'm submitting through my log in form, just like how a typical hashed password is suppose to work. I'm using spring security and spring boot, and so far I know that the log in form is working because I get the error Encoded password does not look like BCrypt. And I know that when I'm submitting the user to the database it's not working because I just see a plain string in the password column in the database. I'm really not sure where I'm going wrong here.
Here's my User object
package com.example.objects;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
import com.example.security.PasswordCrypto;
import com.example.security.RoleEnum;
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Version
private Long version;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "termsOfService")
private Boolean termsOfService;
#OneToMany(mappedBy = "user")
private Set<UserRole> roles;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<QuestionAnswerSet> questionAnswerSet;
public static User createUser(String username, String email, String password) {
User user = new User();
user.username = username;
user.email = email;
user.password = PasswordCrypto.getInstance().encrypt(password);
if(user.roles == null) {
user.roles = new HashSet<UserRole>();
}
//create a new user with basic user privileges
user.roles.add(
new UserRole(
RoleEnum.USER.toString(),
user
));
return user;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getTermsOfService() {
return termsOfService;
}
public void setTermsOfService(Boolean termsOfService) {
this.termsOfService = termsOfService;
}
public Set<QuestionAnswerSet> getQuestionAnswerSet() {
return questionAnswerSet;
}
public void setQuestionAnswerSet(Set<QuestionAnswerSet> questionAnswerSet) {
this.questionAnswerSet = questionAnswerSet;
}
public Set<UserRole> getRoles() {
return roles;
}
public void setRoles(Set<UserRole> roles) {
this.roles = roles;
}
}
Here's my Security Config
package com.example.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static PasswordEncoder encoder;
#Autowired
private UserDetailsService customUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.csrfTokenRepository(csrfTokenRepository());
http
.authorizeRequests()
.antMatchers("/","/home","/register", "/result").permitAll()
.anyRequest().authenticated();
http
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
if(encoder == null) {
encoder = new BCryptPasswordEncoder();
}
return encoder;
}
private CsrfTokenRepository csrfTokenRepository()
{
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setSessionAttributeName("_csrf");
return repository;
}
}
My user detail service
package com.example.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.dao.UserDao;
import com.example.objects.UserRole;
#Service
#Qualifier("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserDao userDao;
#Transactional
#Override
public UserDetails loadUserByUsername(final String username)
throws UsernameNotFoundException {
com.example.objects.User user = userDao.findByUsername(username);
List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
private User buildUserForAuthentication(com.example.objects.User user,
List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRoleName()));
}
return new ArrayList<GrantedAuthority>(setAuths);
}
}
And PasswordCrypto
package com.example.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
public class PasswordCrypto {
#Autowired
private PasswordEncoder passwordEncoder;
private static PasswordCrypto instance;
public static PasswordCrypto getInstance() {
if(instance == null) {
instance = new PasswordCrypto();
}
return instance;
}
public String encrypt(String str) {
return passwordEncoder.encode(str);
}
}
If anyone knows what I'm doing wrong and could help me out, that would be awesome, also let me know if I need to show anymore code. Thanks in advance.
Use encoder to user repository like this :
public class UserRepositoryService implements UserService {
private PasswordEncoder passwordEncoder;
private UserRepository repository;
#Autowired
public UserRepositoryService(PasswordEncoder passwordEncoder,
UserRepository repository) {
this.passwordEncoder = passwordEncoder;
this.repository = repository;
}
private boolean emailExist(String email) {
User user = repository.findByEmail(email);
if (user != null) {
return true;
}
return false;
}
private String encodePassword(RegistrationForm dto) {
String encodedPassword = null;
if (dto.isNormalRegistration()) {
encodedPassword = passwordEncoder.encode(dto.getPassword());
}
return encodedPassword;
}
#Transactional
#Override
public User registerNewUserAccount(RegistrationForm userAccountData)
throws DuplicateEmailException {
if (emailExist(userAccountData.getEmail())) {
LOGGER.debug("Email: {} exists. Throwing exception.",
userAccountData.getEmail());
throw new DuplicateEmailException("The email address: "
+ userAccountData.getEmail() + " is already in use.");
}
String encodedPassword = encodePassword(userAccountData);
User.Builder user = User.getBuilder().email(userAccountData.getEmail())
.firstName(userAccountData.getFirstName())
.lastName(userAccountData.getLastName())
.password(encodedPassword)
.background(userAccountData.getBackground())
.purpose(userAccountData.getPurpose());
if (userAccountData.isSocialSignIn()) {
user.signInProvider(userAccountData.getSignInProvider());
}
User registered = user.build();
return repository.save(registered);
}
}
For morre info, check out this repo
https://bitbucket.org/sulab/biobranch/src/992791aa706d0016de8634ebb6347a81fe952c24/src/main/java/org/scripps/branch/entity/User.java?at=default&fileviewer=file-view-default
My problem was that I needed to add user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword())); in my UserController Post method right before I saved the user
I am trying to access FacesContext in Servlet Filter,
And sometimes (not everytime) i encounter internal server errors.
AuthenticationFilter.java
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
public class AuthenticationFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
UserDetailsBean userBean = null;
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
FacesContext context = FacesUtil.getFacesContext(req, res);
String param = req.getParameter("PARAMETER_VALUES");
if((param!=null && param.isEmpty()) || !isAuthenticated(req)) {
if(param != null && !param.isEmpty()) {
userBean = new UserDetailsBean();
setCookies(param, userBean, req, res);
FacesUtil.setManagedBeanInView(context, "userDetailsBean", userBean);
request.setAttribute("userDetailsBean", userBean);
chain.doFilter(request, response);
}
else {
String homePage = "http://homePage";
res.sendRedirect(homePage);
}
}
else {
try {
if(!context.isPostback()){
userBean = getUserBeanFromCookies(req.getCookies());
request.setAttribute("userDetailsBean", userBean);
}
} catch(Exception e) {
userBean = getUserBeanFromCookies(req.getCookies());
request.setAttribute("userDetailsBean", userBean);
}
chain.doFilter(request, response);
}
}
private UserDetailsBean getUserBeanFromCookies(Cookie[] cookies) {
UserDetailsBean userBean = new UserDetailsBean();
for(Cookie c: cookies) {
String cName = c.getName();
if("userId".equals(cName)) {
userBean.setUserNbr(c.getValue());
}
else if("userEmail".equals(cName)) {
userBean.setEmail(c.getValue());
}
else if("firstName".equals(cName)) {
userBean.setFirstName(c.getValue());
}
else if("lastName".equals(cName)) {
userBean.setLastName(c.getValue());
}
}
return userBean;
}
private boolean setCookies(String param, UserDetailsBean userBean, HttpServletRequest request, HttpServletResponse response) {
boolean validUser = false;
if(param != null) {
String strParams = new String(Base64.decodeBase64(param.getBytes()));
String[] pairs = strParams.split("&");
for(String pp: pairs) {
String[] s = pp.split("=");
if("p_userid".equals(s[0])) {
userBean.setUserNbr(s[1]);
validUser = true;
}
else if("p_email".equals(s[0])){
userBean.setEmail(s[1]);
}
else if("p_first_name".equals(s[0])) {
userBean.setFirstName(s[1]);
}
else if("p_last_name".equals(s[0])) {
userBean.setLastName(s[1]);
}
}
}
if(validUser) {
String cookiePath = "/";
Cookie cookie = new Cookie("userId", userBean.getUserNbr());
cookie.setMaxAge(-1); // Expire time. -1 = by end of current session, 0 = immediately expire it, otherwise just the lifetime in seconds.
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("userEmail", userBean.getEmail());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("firstName",userBean.getFirstName());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
cookie = new Cookie("lastName", userBean.getLastName());
cookie.setMaxAge(-1);
cookie.setPath(cookiePath);
response.addCookie(cookie);
}
return validUser;
}
public boolean isAuthenticated(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if(cookies == null) {
return false;
}
for(Cookie c: cookies) {
String cName = c.getName();
if("userId".equals(cName)) {
if(c.getValue() == null || c.getValue().isEmpty()) {
return false;
}
else {
return true;
}
}
}
return false;
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
UserDetailsBean.java
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ViewScoped
#ManagedBean(name="userDetailsBean")
public class UserDetailsBean implements Serializable {
private String userNbr;
private String email;
private String firstName;
private String lastName;
public String getUserNbr() {
return userNbr;
}
public void setUserNbr(String userNbr) {
this.userNbr = userNbr;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
FacesUtil.java
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FacesUtil {
public static FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "");
facesContext.setViewRoot(view);
FacesContextWrapper.setCurrentInstance(facesContext);
}
return facesContext;
}
// Wrap the protected FacesContext.setCurrentInstance() in a inner class.
private static abstract class FacesContextWrapper extends FacesContext {
protected static void setCurrentInstance(FacesContext facesContext) {
FacesContext.setCurrentInstance(facesContext);
}
}
}
Here the authentication is actually handling by other application,
Once the user login it will send a request parameter (PARAMETER_VALUES) with some information.
We are using JSF 2.1.9 & Tomcat 6.0.35.
i am getting an error at this line from Filter
FacesContext context = FacesUtil.getFacesContext(req, res);
Error stack trace:
Exception=java.lang.NullPointerException
at org.apache.catalina.connector.Request.parseParameters(Request.java:2599)
at org.apache.catalina.connector.Request.getParameter(Request.java:1106)
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:355)
at javax.servlet.ServletRequestWrapper.getParameter(ServletRequestWrapper.java:158)
at com.sun.faces.context.RequestParameterMap.containsKey(RequestParameterMap.java:99)
at java.util.Collections$UnmodifiableMap.containsKey(Collections.java:1280)
at com.sun.faces.renderkit.ResponseStateManagerImpl.isPostback(ResponseStateManagerImpl.java:84)
at com.sun.faces.context.FacesContextImpl.isPostback(FacesContextImpl.java:207)
at com.sandbox.external.site.test.filter.AuthenticationFilter.doFilter(AuthenticationFilter.java:36)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.ha.tcp.ReplicationValve.invoke(ReplicationValve.java:347)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:396)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
When i see the source code of Tomcat 6.0.35 at the line stated in error,
if (!getMethod().equalsIgnoreCase("POST"))
return;
cannot find much information here.
You cannot access the FacesContext in a filter because the FacesContext is initialized by the FacesServlet, and your filter is processed before the request arrives to the servlet.
If it works sometimes, it is probably because of a side effect (JSF creates one FacesContext for every request, every request is bound to a Thread and Threads are reused by the servlet container).
I'm also wondering why are you trying to reinvent the wheel by implementing you own security filters. There is already existing solution which are available (like Spring Security or standard JEE security) and well tested.
See this question for more information from BalusC:
How do I retrieve the FacesContext within a Filter
I want to implement a custom ValueStack in my application by extending the OgnlValueStack class of Struts 2.3.x.
Please let me know how to accomplish this. What classes do I need to extend and implement in my application and how to inject different dependencies using the #Inject annotation?
Update
I have made the changes as suggested earlier. My ValueStackFactory implementation is:
package jp.co.spectrum.insight.core.mvc.factory;
import java.util.Map;
import java.util.Set;
import jp.co.spectrum.insight.core.datamodel.InsightValueStackImpl;
import ognl.MethodAccessor;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.conversion.NullHandler;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.ognl.OgnlNullHandlerWrapper;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
public class InsightValueStackFactory implements ValueStackFactory {
#Inject
private XWorkConverter xworkConverter;
private CompoundRootAccessor compoundRootAccessor;
#Inject("system")
private TextProvider textProvider;
#Inject
private Container container;
private boolean allowStaticMethodAccess;
/*
private static ValueStackFactory instance;
public static ValueStackFactory getInstance() {
if (instance == null) {
instance = new InsightValueStackFactory();
}
return instance;
}
*/
private static ValueStackFactory factory = new InsightValueStackFactory();
public static void setFactory(ValueStackFactory factoryParam) {
factory = factoryParam;
}
public static ValueStackFactory getFactory() {
return factory;
}
public void setXWorkConverter(XWorkConverter conv) {
this.xworkConverter = conv;
}
public void setTextProvider(TextProvider textProvider) {
this.textProvider = textProvider;
}
#Inject(value="allowStaticMethodAccess", required=true)
public void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = "true".equalsIgnoreCase(allowStaticMethodAccess);
}
public ValueStack createValueStack() {
ValueStack stack = new InsightValueStackImpl(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
container.inject(stack);
stack.getContext().put(ActionContext.CONTAINER, container);
return stack;
}
public ValueStack createValueStack(ValueStack stack) {
ValueStack result = new InsightValueStackImpl(stack, xworkConverter, compoundRootAccessor, allowStaticMethodAccess);
container.inject(result);
stack.getContext().put(ActionContext.CONTAINER, container);
return result;
}
public void setContainer(Container container) throws ClassNotFoundException {
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
if (Map.class.isAssignableFrom(cls)) {
PropertyAccessor acc = container.getInstance(PropertyAccessor.class, name);
}
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
}
}
}
names = container.getInstanceNames(MethodAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
}
}
names = container.getInstanceNames(NullHandler.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
}
}
if (compoundRootAccessor == null) {
throw new IllegalStateException("Couldn't find the compound root accessor");
}
this.container = container;
}
}
The InsightValueStackImpl class is my customized ValueStack and it extends the OgnlValueStack.
After the changes as suggested earlier, when I start the application, I get the following error:
java.lang.IllegalArgumentException: Wrapped type converter cannot be null
at com.opensymphony.xwork2.ognl.OgnlTypeConverterWrapper.<init>(OgnlTypeConverterWrapper.java:32)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setRoot(OgnlValueStack.java:88)
at com.opensymphony.xwork2.ognl.OgnlValueStack.<init>(OgnlValueStack.java:71)
at jp.co.spectrum.insight.core.datamodel.InsightValueStackImpl.<init>(InsightValueStackImpl.java:86)
at jp.co.spectrum.insight.core.mvc.factory.InsightValueStackFactory.createValueStack(InsightValueStackFactory.java:85)
at jp.co.spectrum.insight.core.mvc.dispatcher.InsightFilterDispatcher.<init>(InsightFilterDispatcher.java:118)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4072)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4726)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
This is because of null XWorkConverter instance.
Please let me know why it is not getting injected.
Thanks in advance
Thanks
I have made the changes as suggested earlier.
My ValueStackFactory implementation is:
package jp.co.spectrum.insight.core.mvc.factory;
import java.util.Map;
import java.util.Set;
import jp.co.spectrum.insight.core.datamodel.InsightValueStackImpl;
import ognl.MethodAccessor;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.conversion.NullHandler;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.ognl.OgnlNullHandlerWrapper;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
public class InsightValueStackFactory implements ValueStackFactory {
#Inject
private XWorkConverter xworkConverter ;
private CompoundRootAccessor compoundRootAccessor ;
#Inject("system")
private TextProvider textProvider ;
#Inject
private Container container;
private boolean allowStaticMethodAccess;
/*private static ValueStackFactory instance;
public static ValueStackFactory getInstance(){
if(instance==null){
instance = new InsightValueStackFactory();
}
return instance;
}*/
private static ValueStackFactory factory = new InsightValueStackFactory();
public static void setFactory(ValueStackFactory factoryParam) {
factory = factoryParam;
}
public static ValueStackFactory getFactory() {
return factory;
}
public void setXWorkConverter(XWorkConverter conv) {
this.xworkConverter = conv;
}
public void setTextProvider(TextProvider textProvider) {
this.textProvider = textProvider;
}
#Inject(value="allowStaticMethodAccess", required=true)
public void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = "true".equalsIgnoreCase(allowStaticMethodAccess);
}
public ValueStack createValueStack() {
ValueStack stack = new InsightValueStackImpl(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
container.inject(stack);
stack.getContext().put(ActionContext.CONTAINER, container);
return stack;
}
public ValueStack createValueStack(ValueStack stack) {
ValueStack result = new InsightValueStackImpl(stack, xworkConverter, compoundRootAccessor, allowStaticMethodAccess);
container.inject(result);
stack.getContext().put(ActionContext.CONTAINER, container);
return result;
}
public void setContainer(Container container) throws ClassNotFoundException {
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
if (Map.class.isAssignableFrom(cls)) {
PropertyAccessor acc = container.getInstance(PropertyAccessor.class, name);
}
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
}
}
}
names = container.getInstanceNames(MethodAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
}
}
names = container.getInstanceNames(NullHandler.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
}
}
if (compoundRootAccessor == null) {
throw new IllegalStateException("Couldn't find the compound root accessor");
}
this.container = container;
}
}
The InsightValueStackImpl class is my customized ValueStack and it extends the OgnlValueStack.
After the changes as suggested earlier, when I start the application, I get the following error:
java.lang.IllegalArgumentException: Wrapped type converter cannot be null
at com.opensymphony.xwork2.ognl.OgnlTypeConverterWrapper.(OgnlTypeConverterWrapper.java:32)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setRoot(OgnlValueStack.java:88)
at com.opensymphony.xwork2.ognl.OgnlValueStack.(OgnlValueStack.java:71)
at jp.co.spectrum.insight.core.datamodel.InsightValueStackImpl.(InsightValueStackImpl.java:86)
at jp.co.spectrum.insight.core.mvc.factory.InsightValueStackFactory.createValueStack(InsightValueStackFactory.java:85)
at jp.co.spectrum.insight.core.mvc.dispatcher.InsightFilterDispatcher.(InsightFilterDispatcher.java:118)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:115)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4072)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4726)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
This is because of null XWorkConverter instance.
Please let me know why it is not getting injected.
Thanks in advance
You need to implement a ValueStackFactory and register it in your struts.xml, as follows:
<bean type="com.opensymphony.xwork2.util.ValueStackFactory"
name="yourOgnlValueStackFactory"
class="com.example.YourOgnlValueStackFactory" />
Then, set your implementation as the factory to use, using:
<constant name="struts.valueStackFactory" value="yourOgnlValueStackFactory"/>
Update
I'm not sure if you are able to mix field and method injection like you are doing. Try moving the #Inject annotations back to the setter methods and see if that resolves the issue.
I am developing a Web App with following :
Glassfish v3.1.2
Eclipse Juno SR2
JPA EclipseLink2.0
JSF 2.0
I have different set of pages for the normal user and for admin users. While trying to setup a page filter during login i am getting this error in my login bean : javax.faces.FacesException: #{loginBean.login}: java.lang.NullPointerException
My whole login code works without this part
if (uGDB.validateGroup(username, adminGroup)) {
return "home.jsf?faces-redirect=true&includeViewParams=true";
}
return "normalHome.jsf?faces-redirect=true&includeViewParams=true"
;
What I am trying to do here is to get the Group Id of the user who is logging in and check if it is admin or not. And accordingly I want to direct the user to the corresponding page. This is because i have different set of pages for admin users and normal users. I don't want to use the Glassfish Realms because the end user doesn't require it.
Can someone please help me identify where I am going wrong in this. (Please excuse me for stupid mistakes I am just starting with such an development). Thanks a lot in advance!
Below is the code for my loginBean
package beans;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import ejb.UserDaoBean;
import ejb.UserGroupDaoBean;
import model.User;
#ManagedBean(name = "loginBean")
#RequestScoped
public class LoginBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#EJB
private UserDaoBean uDB;
private UserGroupDaoBean uGDB;
private User userId;
private int adminGroup = 1;
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String login() {
FacesContext context = FacesContext.getCurrentInstance();
if (uDB.validateUser(username)) {
userId = uDB.findUser(username);
context.getExternalContext().getSessionMap().put("userId", userId);
if (uGDB.validateGroup(username, adminGroup)) {
return "home.jsf?faces-redirect=true&includeViewParams=true";
}
return "normalHome.jsf?faces-redirect=true&includeViewParams=true";
} else {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary("Username doesn't exists! OR User is trying to login from someone else's account");
context.addMessage("", message);
return null;
}
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext()
.invalidateSession();
return "logout.jsf?faces-redirect=true";
}
}
Here is the complete error stack from Glassfish log
WARNING: #{loginBean.login}: java.lang.NullPointerException
javax.faces.FacesException: #{loginBean.login}: java.lang.NullPointerException
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.faces.el.EvaluationException: java.lang.NullPointerException
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
... 31 more
Caused by: java.lang.NullPointerException
at beans.LoginBean.login(LoginBean.java:49)
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 com.sun.el.parser.AstValue.invoke(AstValue.java:254)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
... 32 more
Here is my controller class
package ejb;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.PersistenceContext;
import model.Group;
import model.User;
import model.UserGroup;
#Stateful
#LocalBean
public class UserGroupDaoBean {
#PersistenceContext(unitName = "myPU")
private EntityManager entityManager;
public UserGroupDaoBean() {
}
public UserGroup createNewUserGroup(int groupId, String username) {
UserGroup newUserGrp = new UserGroup();
User myUsr;
myUsr = entityManager.find(User.class, username);
newUserGrp.setUser(myUsr);
Group myGrp;
myGrp = entityManager.find(Group.class, groupId);
newUserGrp.setGroup(myGrp);
saveNewUsrGrp(newUserGrp);
return newUserGrp;
}
private void saveNewUsrGrp(UserGroup usrGrp) {
entityManager.persist(usrGrp);
entityManager.flush();
}
public boolean checkUsertoGroup(String username, int groupId) {
Group chkGrp;
chkGrp = entityManager.find(Group.class, groupId);
User chkUsr;
chkUsr = entityManager.find(User.class, username);
if (chkGrp != null) {
if (chkUsr != null) {
try {
entityManager.createNamedQuery("findGroupsbyUser")
.setParameter("username", chkUsr)
.setParameter("groupId", chkGrp).getSingleResult();
System.out.println("UserGroup already exists");
return false;
} catch (NoResultException e) {
return true;
}
}
System.out.println("User doesn't exist");
return false;
}
System.out.println("Group doesn't exist");
return false;
}
public void deleteUserGroup(UserGroup userGroup) {
userGroup = entityManager.merge(userGroup);
entityManager.remove(userGroup);
}
public UserGroup update(UserGroup myUserGroup) {
return entityManager.merge(myUserGroup);
}
#SuppressWarnings("unchecked")
public List<UserGroup> getAllUserGroups() {
try {
Query query = entityManager.createNamedQuery("findAllUserGroup");
List<UserGroup> result = (List<UserGroup>) query.getResultList();
return result;
} catch (NoResultException e) {
System.out.println("No Result found");
return null;
}
}
public boolean validateGroup(String username, int groupId) {
try {
UserGroup myGroupId = (UserGroup) entityManager
.createNamedQuery("findGroup")
.setParameter("username", username)
.setParameter("groupId", groupId).getSingleResult();
if (myGroupId != null) {
System.out.println("This user is admin!!!");
return true;
}
} catch (NoResultException e) {
return false;
}
System.out.println("This user is not admin");
return false;
}
}
Below is my entity UserGroup
package model;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the UserGroup database table.
*
*/
#NamedQueries({
#NamedQuery(name = "findGroupsbyUser", query = "Select ug.group from UserGroup ug where ug.user=:username AND ug.group=:groupId"),
#NamedQuery(name = "findAllUserGroup", query="Select ug from UserGroup ug"),
#NamedQuery(name = "findAdminGroupId", query = "Select ug from UserGroup ug where ug.user=:username AND ug.group=:groupId"),
})
#Entity
#Table(name="usergroup")
public class UserGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="RowId" )
private int rowId;
//bi-directional many-to-one association to Group
#ManyToOne
#JoinColumn(name="groupId")
private Group group;
//bi-directional many-to-one association to User
#ManyToOne
#JoinColumn(name="username")
private User user;
public UserGroup() {
}
public int getRowId() {
return this.rowId;
}
public void setRowId(int rowId) {
this.rowId = rowId;
}
public Group getGroup() {
return this.group;
}
public void setGroup(Group group) {
this.group = group;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
}
Read the stack trace: the NPE is thrown at line 49 of LoginBean.java.
With high probability, uGBD is null, because the EJB annotation is missing. You need to use the #EJB annotation in front of each of the EJBs you are injecting:
#EJB
private UserDaoBean uDB;
#EJB
private UserGroupDaoBean uGDB;
...