Spring security authentication fails - java

I am using Spring security version 3.1.4.RELEASE. When I try to login to the application I am getting an error. I have cross checked the credentials in DB. Even though the credentials are correct the system is not lettng me to login. Following the details of error and my configuration settings.
Getting following error while trying to login to the system:
web.security.auth.CustomUsernamePasswordAuthenticationFilter username is support
web.security.auth.CustomUsernamePasswordAuthenticationFilter password is [PROTECTED]
web.security.auth.CustomUsernamePasswordAuthenticationFilter authRequest is org.springframework.security.authentication.UsernamePasswordAuthenticationToken#4a159a52: Principal: support; Credentials: [PROTECTED]; Authenticated: false; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#0: RemoteIpAddress: 204.238.52.177; SessionId: 9B49838B0DF4224E169EAF425C0AABE9; Not granted any authorities
web.security.auth.CustomUsernamePasswordAuthenticationFilter Authentication manager was com.sun.proxy.$Proxy476
System.out loadUserByUsername support enter
org.springframework.security.authentication.event.LoggerListener Authentication event AuthenticationFailureServiceExceptionEvent: support; details: org.springframework.security.web.authentication.WebAuthenticationDetails#0: RemoteIpAddress: 204.238.52.177; SessionId: 9B49838B0DF4224E169EAF425C0AABE9; exception: null
Here I am getting the exception as null!
Config:
<authentication-manager alias="authenticationManager">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<beans:bean id="plaintextPasswordEncoder" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder" />
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="daoUserDetailsService" />
<beans:property name="passwordEncoder" ref="plaintextPasswordEncoder" />
</beans:bean>
<beans:bean id="daoUserDetailsService" class="web.security.auth.DAOUserDetailsService">
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
<beans:bean id="dataSource" class="web.security.auth.DAODataSource" />
<beans:bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map request-matcher="ant">
<filter-chain pattern="/**" filters="channelProcessingFilter, SecurityContextPersistenceFilter, logoutFilter, authenticationFilter, anonymousAuthFilter, exceptionTranslationFilter, filterSecurityInterceptor" />
</filter-chain-map>
</beans:bean>
<beans:bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
<beans:property name="channelDecisionManager" ref="channelDecisionManager"/>
<beans:property name="securityMetadataSource">
<filter-security-metadata-source request-matcher="ant">
<intercept-url pattern="/**" access="REQUIRES_SECURE_CHANNEL"/>
</filter-security-metadata-source>
</beans:property>
</beans:bean>
<beans:bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl">
<beans:property name="channelProcessors">
<beans:list>
<beans:ref bean="secureChannelProcessor"/>
<beans:ref bean="insecureChannelProcessor"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor" />
<beans:bean id="insecureChannelProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor" />
<beans:bean id="SecurityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
<beans:bean id="authenticationFilter" class="web.security.auth.CustomUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="filterProcessesUrl" value="/j_spring_security_check"/>
<beans:property name="usernameParameter" value="username"/>
<beans:property name="passwordParameter" value="password"/>
</beans:bean>
<beans:bean id="anonymousAuthFilter" class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<beans:property name="key" value="foobar"/>
<beans:property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</beans:bean>
<beans:bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<beans:property name="key" value="foobar"/>
</beans:bean>
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="accessDecisionManager" ref="accessDecisionManager"/>
<beans:property name="securityMetadataSource">
<filter-security-metadata-source>
<intercept-url pattern="/LoginPage" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/LoginExpiredPage" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/wicket/bookmarkable/web.sec.pages.LoginExpiredPage" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/css/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/images/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/*.png" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/*.ico" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/wicket/resource/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED"/>
</filter-security-metadata-source>
</beans:property>
</beans:bean>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:bean class="org.springframework.security.access.vote.RoleVoter">
<beans:property name="rolePrefix" value="ROLE_"/>
</beans:bean>
<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg value="/" />
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</beans:list>
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout"/>
</beans:bean>
<beans:bean id="forceCookieUseFilter" class="web.security.ForceCookieUseFilter">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/LoginPage"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/accessDenied.htm"/>
</beans:bean>
<beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener"/>
AuthenticationFilter class as follows:
public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
private boolean postOnly = true;
public CustomUsernamePasswordAuthenticationFilter() {
super("/j_spring_security_check");
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
if(this.getAuthenticationManager()==null){
logger.info("Authentication manager is null.");
} else {
logger.info("Authentication manager was "+this.getAuthenticationManager().getClass().getName());
}
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(passwordParameter);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(usernameParameter);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setUsernameParameter(String usernameParameter) {
this.usernameParameter = usernameParameter;
}
public void setPasswordParameter(String passwordParameter) {
this.passwordParameter = passwordParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getUsernameParameter() {
return usernameParameter;
}
public final String getPasswordParameter() {
return passwordParameter;
}
}
UserDetails class as follows:
public class DAOUserDetailsService implements UserDetailsService {
private DataSource dataSource;
public void setDataSource(DAODataSource dataSource) {
this.dataSource = dataSource;
}
public DAOUserDetailsService () { }
public DAOUserDetailsService (DAODataSource dataSource) {
this.dataSource = dataSource;
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
DataSource ds = dataSource;
PreparedStatement userStatement = null;
try {
Connection con = ds.getConnection();
String userQuery = "SELECT USER_ID, USER_PASSWORD, USER_ENABLED FROM USER WHERE USER_ID = ?";
userStatement = con.prepareStatement(userQuery);
userStatement.setString(0, username);
ResultSet userResults = userStatement.executeQuery();
if (userResults.next()) {
final SimpleGrantedAuthority supervisorAuthority = new SimpleGrantedAuthority(
"supervisor");
final SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority(
"user");
Collection<GrantedAuthority> authorityList = new ArrayList<GrantedAuthority>();
authorityList.add(supervisorAuthority);
authorityList.add(userAuthority);
return new User(userResults.getString(0), userResults.getString(1), authorityList);
}
throw new UsernameNotFoundException(username);
} catch (SQLException e) {
throw new UsernameNotFoundException(e.toString());
}
finally {
if (userStatement != null) {
try {
userStatement.close();
} catch (SQLException e) {
throw new UsernameNotFoundException(e.toString());
}
}
}
}
}
Kindly provide some idea on the issue.
Thanks in advance.

You can create your implementation of LoggerListener for investigate more the causes.
public class LoggerListener implements ApplicationListener<AbstractAuthorizationEvent> {
private static final Log logger = LogFactory.getLog(LoggerListener.class);
public void onApplicationEvent(AbstractAuthorizationEvent event) {
//investigation code
}
}
I had a very similar problem and the cause was one ClassCastException in other part of code, one controller.

In your class DAOUserDetailsService:
...
return new User(userResults.getString(0), userResults.getString(1), new ArrayList<GrantedAuthority>());
...
you return UserDeatils with empty authorities. So your user is loged in but he has no roles (not authorised).

You have to add ROLE_ prefix to role while creating your GrantedAuthority. So you code should look like:
// For xxx
final SimpleGrantedAuthority supervisorAuthority = new SimpleGrantedAuthority(
"ROLE_xxx");
Alternative: You can clear default prefix in RoleVoter but IMO this is not a good choice because ROLE_ prefix actually helps RoleVoter to understand what remaning string is.
<bean id="roleVoter" class="org.springframework.security.vote.RoleVoter">
<property name="rolePrefix" value=""></property>
</bean>

Related

Spring security with oauth2 adding additional parameters to authorization URL?

I have implemented Spring Security in my restful web service. In fact, I have to add an extra parameter with the request from client side and should fetch it from the service when request for authentication/accesstoken.
spring-security.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd ">
<!-- #author Nagesh.Chauhan(neel4soft#gmail.com) -->
<!-- This is default url to get a token from OAuth -->
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- This is where we tells spring security what URL should be protected
and what roles have access to them -->
<http pattern="/api/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/api/**" access="ROLE_APP" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<!-- Custom User details service which is provide the user data -->
<bean id="customUserDetailsService"
class="com.weekenter.www.service.impl.CustomUserDetailsService" />
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="plaintext">
</password-encoder>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- This defined token store, we have used inmemory tokenstore for now
but this can be changed to a user defined one -->
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<!-- This is where we defined token based configurations, token validity
and other things -->
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="120" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices" />
</bean>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="test" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<!-- client -->
<oauth:client client-id="restapp"
authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_APP" scope="read,write,trust" secret="secret" />
<oauth:client client-id="restapp"
authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="restapp" authorities="ROLE_APP" />
</oauth:client-details-service>
<sec:global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the
http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
CustomUserDetailsService
#Service
#Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private LoginDao loginDao;
public UserDetails loadUserByUsername(String login)
throws UsernameNotFoundException {
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
com.weekenter.www.entity.User user = null;
try {
user = loginDao.getUser(login);
if (user != null) {
if (user.getStatus().equals("1")) {
enabled = false;
}
} else {
throw new UsernameNotFoundException(login + " Not found !");
}
} catch (Exception ex) {
try {
throw new Exception(ex.getMessage());
} catch (Exception ex1) {
}
}
return new User(
user.getEmail(),
user.getPassword(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities()
);
}
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles());
return authList;
}
public List<String> getRoles() {
List<String> roles = new ArrayList<String>();
roles.add("ROLE_APP");
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
Currently I am requesting with the URL:
http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo#codelynks.com&password=mypass
And I will get the response
{
"access_token":"76e928b2-45e2-4283-88a4-6c01f41b51d3","token_type":"bearer","refresh_token":"8748e8ad-79c1-465d-94fe-13394eea370d","expires_in":119
}
I have to enhance it by adding additional parameter deviceToken.
And the URL would be:
http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo#codelynks.com&password=mypass&deviceToken=something
I have treid by implementing UsernamePasswordAuthenticationFilter, but it didn't work. How can I get the deviceToken parameter from the web service without affecting the output?
http://localhost:8084/Domain/oauth/token?grant_type=password&client_id=restapp&client_secret=restapp&username=anoo#codelynks.com&password=mypass&additional_param=abc123
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
log.info("additional_param: " + request.getParameter("additional_param"));
log will show
additional_param: abc123
Although AOP is used when it comes to crosscutting concerns, this approach worked as expected and I think It is a valid approach.
#Aspect
public class Oauth2Aspect {
#AfterReturning("execution( * org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
public void executeAfterAuthentication() throws Exception {
System.out.println(":Authentication done");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
System.out.println(":Authentication done " + request.getParameter("deviceInfo"));
}
}

Promoting header values from a file to job execution context

I have a file where the first line contains the field names as headers as below:
Id;ToyName;ToyType;ToyColor
1;abc;abc;red
2;pqr;pqr;blue
3;xyz;xyz;orange
My reader is as below:
<beans:bean id="MyFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<beans:property name="linesToSkip" value="1"/>
<beans:property name="skippedLinesCallback" ref="headerSkipCallback" />
<beans:property name="resource" ref="MyInputFileResource" />
<beans:property name="lineMapper">
<beans:bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<beans:property name="lineTokenizer">
<beans:bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<beans:property name="delimiter" value=";"/>
<beans:property name="names" value="#{jobExecutionContext['columnsFromFileHeader']}" />
</beans:bean>
</beans:property>
<beans:property name="fieldSetMapper">
<beans:bean class="mypackage.MyFieldSetMapper">
</beans:bean>
</beans:property>
</beans:bean>
</beans:property>
</beans:bean>
Thus I have a header line call back implemented to read the skipped header line.
<beans:bean id="headerSkipCallback" class="mypackage.HeaderLineHandler" scope="step">
</beans:bean>
and the class as:
public class HeaderLineHandler implements LineCallbackHandler {
public void handleLine(final String headerLine) {
System.out.println(headerLine);
}}
This works correctly and the header line from the file gets printed.
Now I want to use these field names from file header in the names property of DefaultLineTokenizer
So to put the header line inside the context, I implemented a context injector class as below:
public class StepExecutionListenerCtxInjector {
private ExecutionContext stepExecutionCtx;
private ExecutionContext jobExecutionCtx;
#BeforeStep
public void beforeStep(final StepExecution stepExecution) {
this.stepExecutionCtx = stepExecution.getExecutionContext();
this.jobExecutionCtx = stepExecution.getJobExecution().getExecutionContext();
}
public ExecutionContext getStepExecutionCtx() {
return this.stepExecutionCtx;
}
public ExecutionContext getJobExecutionCtx() {
return this.jobExecutionCtx;
}
}
And changed my header line handler to:
<beans:bean id="headerSkipCallback" class="mypackage.HeaderLineHandler" scope="step">
<beans:property name="stepExecutionListener" ref="stepExecutionListener" />
</beans:bean>
and the class as:
public class HeaderLineHandler implements LineCallbackHandler {
private StepExecutionListenerCtxInjector stepExecutionListener;
public void handleLine(final String headerLine) {
this.stepExecutionListener.getJobExecutionCtx().put("columnsFromFileHeader", headerLine.replaceAll(";", ","));
}
// getter setters
}
Here I am saving the header line as columnsFromFile key inside the job execution context.
However, when I am trying to access it in DefaultLineTokenizer as:
<beans:property name="names" value="#{jobExecutionContext['columnsFromFileHeader']}" />
I am getting null pointer exception:
org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2 in resource=[file [C:\myFile.dat]], input=[1;abc;abc;red]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:182)
Caused by:
java.lang.NullPointerException
at org.springframework.batch.item.file.transform.AbstractLineTokenizer.tokenize(AbstractLineTokenizer.java:113)
How can I use the header line from the file in the property to DefaultLineTokenizer?
Make DelimitedLineTokenizer a non-anonymous bean and inject it into your HeaderLineHandler; in HeaderLineHandler.handleLine() set DelimitedLineTokenizer.names using handleLine() input param.
I can't test it but should works.

Spring JDBCTemplate + Transaction Manager memory leak

i have really strange problem. My Spring web-application seems to have a memory-leak.
i'm using Spring 3.2
my Tomcat config:
JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m
-XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=128m
-XX:MaxPermSize=256m -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dumps"
my dataSource declaration:
<!-- declare transactionManager -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<beans:bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<beans:property name="dataSource" ref="dataSource"></beans:property>
</beans:bean>
<beans:bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url" value="jdbc:mysql://localhost/test" />
<beans:property name="username" value="User" />
<beans:property name="password" value="password" />
<beans:property name="initialSize" value="5" />
<beans:property name="maxActive" value="55" />
<beans:property name="maxIdle" value="20" />
<beans:property name="minIdle" value="10" />
<beans:property name="maxWait" value="10000" />
<beans:property name="minEvictableIdleTimeMillis" value="55000" />
<beans:property name="timeBetweenEvictionRunsMillis" value="34000" />
<beans:property name="validationQuery" value="SELECT 1" />
<beans:property name="testOnBorrow" value="true" />
<beans:property name="removeAbandoned" value="true"/>
<beans:property name="removeAbandonedTimeout" value="60"/>
<beans:property name="logAbandoned" value="true"/>
</beans:bean>
<beans:bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource" ref="dataSource"></beans:property>
</beans:bean>
i'm injecting the jdbcTemplate into dao. I'm using Transaction-Annotations as well.
this is what i got from Memory Analizer (MAT):
The class "com.mysql.jdbc.NonRegisteringDriver", loaded by "org.apache.catalina.loader.StandardClassLoader # 0x515c1390", occupies 758.845.296 (72,57%) bytes. The memory is accumulated in one instance of "java.util.concurrent.ConcurrentHashMap$Segment[]" loaded by "system class loader".
in the detail-view i saw this:
com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference
First 10 of 14.360 objects. Number of Objects: 14.360. Used Heap Size: 459.520. Retained Heap Size: 732.819.568
i found this: bug report, but i'm using 5.1.29, so i think i shouldn't have this problem. But maybe the problem is somewhere in apache dbcp. Can someone help me? Is my configuration ok? Is there a problem in JDBCTemplate + TransactionManager?
here is 1 of my services. I use Transactions in the services, is it ok?
#Service
public class ModerationServiceImpl implements ModerationService {
#Autowired
private EventService eventService;
#Autowired
private ContentManagementService cmService;
#Autowired
private IconDao iconDao;
#Transactional(rollbackFor = Exception.class)
#Override
public void activateUserIcon(long userIconId, long userId, String comment)
throws IconNotFoundException, NoPermissionException, IOException,
IconNotAssignedToUserException, WrongIconStateException {
if(!iconDao.isAssignedToUser(userIconId))
throw new IconNotAssignedToUserException("icon: " + userIconId + " is not assigned to a user and can't be activated!");
cmService.activateUserIcon(userIconId);
eventService.writeUserIconEvent(userIconId, userId, new Date().getTime(), Enum_ServerEvent.verified, Enum_UserIconState.approved, comment);
}
and here is 1 of my DAO's:
#Repository
public class IconDaoImpl extends DB_Contract implements IconDao{
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public IconData getUserIconById(long iconId) throws IconNotFoundException {
String sql = SELECT + UserIcon.CN_ServerID + NEXT +
UserIcon.CN_State + NEXT +
UserIcon.CN_Ref +
FROM + UserIcon.TABLE_NAME + WHERE + UserIcon.CN_ServerID + " = ?";
try{
return jdbcTemplate.queryForObject(sql, new UserIconRowMapper(), iconId);
}catch (EmptyResultDataAccessException e){
throw new IconNotFoundException("couldn't find icon for id: " + iconId);
}
}

Spring security with Java Config doesn´t work eraseCredentials method

With the following Java Config configuration for Spring Security 3.2.2 and Spring Framework 3.2.8, user passsword is deleted even when I use '.eraseCredentials(false)' and it's not available using authentication.getCredentials().
#Configuration
#EnableWebSecurity
#Order( 1 )
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean( name = "authenticationEntryPoint" )
public LoginUrlAuthenticationEntryPoint authenticationEntryPoint() {
return new XhrAwareAuthenticationEntryPoint( "/home?noAuthenticated=expired" );
}
#Bean( name = "acessDeniedHandler" )
public AccessDeniedHandler acessDeniedHandler() {
XhrAwareAccessDeniedHandlerImpl xhrAwareAccessDeniedHandler = new XhrAwareAccessDeniedHandlerImpl();
xhrAwareAccessDeniedHandler.setErrorPage( "/denied" );
return xhrAwareAccessDeniedHandler;
}
#Bean( name = "atlasAuthenticationSuccessHandler" )
public AtlasAuthenticationSuccessHandler atlasAuthenticationSuccessHandler() {
return new AtlasAuthenticationSuccessHandler( "/views/hub" );
}
#Bean( name = "atlasAuthenticationFailureHandler" )
public AtlasAuthenticationFailureHandler atlasAuthenticationFailureHandler() {
return new AtlasAuthenticationFailureHandler( "/home?loginError=error" );
}
#Bean( name = "atlasLogoutSuccessHandler" )
public AtlasLogoutSuccessHandler atlasLogoutSuccessHandler() {
AtlasLogoutSuccessHandler atlasLogoutSuccessHandler = new AtlasLogoutSuccessHandler();
atlasLogoutSuccessHandler.setDefaultTargetUrl( "/home?logoff=disconnect" );
return atlasLogoutSuccessHandler;
}
#Override
public void configure( WebSecurity web ) throws Exception {
web.ignoring().antMatchers( "/resources/**" );
}
#Override
protected void configure( HttpSecurity http ) throws Exception {
http.csrf().disable()
.httpBasic()
.authenticationEntryPoint( this.authenticationEntryPoint() )
.and()
.exceptionHandling()
.accessDeniedHandler( this.acessDeniedHandler() )
.and()
.formLogin()
.usernameParameter( "j_username" )
.passwordParameter( "j_password" )
.loginPage( "/home" )
.loginProcessingUrl( "/login" )
.failureHandler( this.atlasAuthenticationFailureHandler() )
.successHandler( this.atlasAuthenticationSuccessHandler() )
.permitAll()
.and()
.logout()
.logoutUrl( "/logout" )
.logoutSuccessHandler( this.atlasLogoutSuccessHandler() )
.invalidateHttpSession( true )
.permitAll()
.and()
.authorizeRequests()
.antMatchers(
ViewsConstants.VIEWS_URI + "/**",
RssController.RSS_URI + "/**",
ProxySolrController.SEARCH_URI + "/**" )
.authenticated()
.antMatchers( ConfigurationProperties.ADMIN_URI + "/**" ).hasAnyRole( Role.ADMIN )
.antMatchers( "/**" ).permitAll();
}
#Configuration
#Profile( "DES" )
public static class AuthenticacioInMemoryConfig {
#Autowired
public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception {
auth.eraseCredentials( false ).inMemoryAuthentication()
.withUser( "user" ).password( "atlas" ).authorities( "ROLE_USER" ).and()
.withUser( "admin" ).password( "atlas" ).authorities( "ROLE_ADMIN" );
}
}
#Configuration
#Profile( "PRO" )
#PropertySource( "file:${config.env}/config_env.properties" )
public static class AuthenticacionLdapConfig {
#Value( "${ldap.host}" )
private String host;
#Value( "${ldap.port}" )
private String port;
#Value( "${ldap.basedn}" )
private String baseDn;
#Value( "${ldap.userdn}" )
private String userDn;
#Value( "${ldap.passw}" )
private String password;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean( name = "contextSource" )
public DefaultSpringSecurityContextSource contextSource() {
DefaultSpringSecurityContextSource contextSource =
new DefaultSpringSecurityContextSource( "ldap://" + this.host + ":" + this.port );
contextSource.setUserDn( this.userDn );
contextSource.setPassword( this.password );
return contextSource;
}
#Bean( name = "userSearch" )
public FilterBasedLdapUserSearch userSearch() {
return new FilterBasedLdapUserSearch( this.baseDn, "(bsalias={0})", this.contextSource() );
}
#Bean( name = "ldapAuthenticator" )
public LdapAuthenticator ldapAuthenticator() {
BindAuthenticator authenticator = new BindAuthenticator( this.contextSource() );
authenticator.setUserSearch( this.userSearch() );
return authenticator;
}
#Bean( name = "atlasAuthoritiesPopulator" )
public AtlasAuthoritiesPopulator atlasAuthoritiesPopulator() {
return new AtlasAuthoritiesPopulator();
}
#Bean( name = "ldapAuthenticationProvider" )
public LdapAuthenticationProvider ldapAuthenticationProvider() {
return new LdapAuthenticationProvider( this.ldapAuthenticator(), this.atlasAuthoritiesPopulator() );
}
#Autowired
public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception {
auth.eraseCredentials( false ).authenticationProvider( this.ldapAuthenticationProvider() );
}
}
}
However, using the xml configuration for the same spring security and spring framework is running ok and the password is available.
<context:property-placeholder location="file:${config.env:}/config_env.properties" />
<global-method-security secured-annotations="enabled"/>
<beans:bean id="authenticationEntryPoint"
class="es.isban.atlas.views.web.core.authentication.XhrAwareAuthenticationEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/home?noAuthenticated=expired"/>
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="es.isban.atlas.views.web.core.authentication.XhrAwareAccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/denied" />
</beans:bean>
<beans:bean id="atlasAuthenticationSuccessHandler"
class="es.isban.atlas.views.web.core.authentication.AtlasAuthenticationSuccessHandler">
<beans:constructor-arg name="defaultTargetUrl" value="/views/hub"/>
</beans:bean>
<beans:bean id="atlasAuthenticationFailureHandler"
class="es.isban.atlas.views.web.core.authentication.AtlasAuthenticationFailureHandler">
<beans:constructor-arg name="defaultFailureUrl" value="/home?loginError=error"/>
</beans:bean>
<beans:bean id="atlasLogoutSuccessHandler"
class="es.isban.atlas.views.web.core.authentication.AtlasLogoutSuccessHandler">
<beans:property name="defaultTargetUrl" value="/home?logoff=disconnect" />
</beans:bean>
<!-- This is where we configure Spring-Security -->
<http use-expressions="true"
entry-point-ref="authenticationEntryPoint">
<access-denied-handler ref="accessDeniedHandler" />
<intercept-url pattern="/*" access="permitAll()"/>
<intercept-url pattern="/views/**" access="isAuthenticated()" />
<intercept-url pattern="/rss/**" access="isAuthenticated()" />
<intercept-url pattern="/search/**" access="isAuthenticated()" />
<intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN')" />
<form-login login-page="/home"
login-processing-url="/login"
authentication-success-handler-ref="atlasAuthenticationSuccessHandler"
authentication-failure-handler-ref="atlasAuthenticationFailureHandler" />
<!-- authentication-failure-url="/home?loginError=error"
default-target-url="/views/hub" -->
<logout logout-url="/logout"
invalidate-session="true"
success-handler-ref="atlasLogoutSuccessHandler" />
<!-- logout-success-url="/home"
delete-cookies="true" -->
</http>
<beans:beans profile="PRO">
<beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<beans:constructor-arg value="ldap://${ldap.host}:${ldap.port}"/>
<beans:property name="userDn" value="${ldap.userdn}"/>
<beans:property name="password" value="${ldap.passw}"/>
</beans:bean>
<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<beans:constructor-arg ref="contextSource"/>
<beans:property name="userSearch">
<beans:bean class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg value="${ldap.basedn}"/>
<beans:constructor-arg value="(bsalias={0})"/>
<beans:constructor-arg ref="contextSource"/>
</beans:bean>
</beans:property>
</beans:bean>
</beans:constructor-arg>
<beans:constructor-arg>
<beans:bean class="es.isban.atlas.views.web.core.authorization.AtlasAuthoritiesPopulator" />
</beans:constructor-arg>
</beans:bean>
<authentication-manager erase-credentials="false">
<authentication-provider ref="ldapAuthProvider" />
</authentication-manager>
</beans:beans>
<beans:beans profile="DES">
<authentication-manager erase-credentials="false">
<authentication-provider>
<user-service>
<user name="user" password="atlas" authorities="ROLE_USER" />
<user name="admin" password="atlas" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Do you have any clue? How can I fix that?
Thanks in advance.
This is a bug in the Spring Security Java Configuration that impacts the global authentication option. See SEC-2533 for details. There is not a real easy work around for this issue, but the bug is already fixed and a release will be out within the next few days.

NullPointerException returned by Query object in DAO using Spring 3 MVC

I'm new in spring, I have 3 projects in my eclipse. One JPA.jar, client.jar and a Web.war.
I am going to deploy these on Tomcat 6 so all the dependencies are mainly on the Web.war.
My problem is that I can persist data in the oracle data base but I cannot get(select) the data from the Query object in the DAO :(.
here is my servlet-context
</beans:bean>
<!-- Oracle Driver -->
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<beans:property name="url" value="jdbc:oracle:thin:#//sapodev.sapo.co.za:1523/P3P"/>
<beans:property name="username" value="pensions"/>
<beans:property name="password" value="pensions"/>
</beans:bean>
<!-- JPA EntityManagerFactory -->
<beans:bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<beans:property name="persistenceUnitName" value="frameworkPU"/>
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="jpaVendorAdapter">
<beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<beans:property name="showSql" value="true"/>
<!-- <property name="generateDdl" value="false"/> -->
<beans:property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<beans:property name="entityManagerFactory" ref="entityManagerFactory" />
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean id="persistenceAnnotation" class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<beans:bean id="contactService" class="za.co.sapo.service.ContactServiceImpl"/>
<context:component-scan base-package="za.co.sapo.controller" />
<context:annotation-config />
<context:component-scan base-package="za.co.sapo.dao"/>
</beans:beans>
Here is the DAO class
public List<DevUserTab> findUsers() {
List<DevUserTab> list = null;
log.info("DD");
try{
TypedQuery<DevUserTab> query = this.entityManagerFactory.createNamedQuery("SELECT d from DevUserTab d", DevUserTab.class);
list= query.getResultList();
} catch(Exception e){
log.info(" EE");
e.printStackTrace();
}
return list;
}
Here is the service class
#Autowired
public ContactDAO contactDAO;
public List findUsers() {
// TODO Auto-generated method stub
ContactDAO contact = new ContactDAO();
List users = contact.findUsers();
return users;
}
My controller
#RequestMapping(value = "/table")
public ModelAndView getContacts(Locale locale, Model model) {
logger.info("Getting the Contacts for us "+ locale.toString());
ModelAndView mv = new ModelAndView("/table");
try{
List<Contact> objects = ServiceLayerContext.getContext().findContacts();
mv.addObject("objects", objects );
} catch(Exception e){
e.printStackTrace();
}
return mv;
}
The createNamedQuery expects you to be referencing a query you configured in your persistence.xml
When specifying the JPQL directly as you are doing, you need to use the createQuery method instead.

Categories