Spring ContentNegotiatingViewResolver - How to use bean name for jsp view not full url with path parameters - spring

My servlet-context file has
<beans:bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<beans:property name="useNotAcceptableStatusCode"
value="false" />
<beans:property name="contentNegotiationManager">
<beans:bean
class="org.springframework.web.accept.ContentNegotiationManager">
<beans:constructor-arg>
<beans:bean
class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
<beans:constructor-arg>
<beans:map>
<beans:entry key="html" value="text/html" />
<beans:entry key="json" value="application/json" />
</beans:map>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
</beans:property>
<beans:property name="viewResolvers">
<beans:list>
<beans:bean
class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<beans:bean id="jspView"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/jsp/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
</beans:list>
</beans:property>
<beans:property name="defaultViews">
<beans:list>
<beans:bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</beans:list>
</beans:property>
</beans:bean>
My Controller File has
#Controller("resources")
public class Resources {
#RequestMapping(value = "/resources/{name}", method = RequestMethod.GET)
public Map getResource(#PathVariable String name) {
return new HashMap();
}
}
But whenever i try to access /server/resources/myfilename.html
Server throws 404 saying /server/WEB-INF/jsp/resources/myfilename.jsp is not found.
But it should load /server/WEB-INF/jsp/resources.jsp as im using BeanNameViewResolver. Please help.

What you get:
Controller return a null view name, so DefaultRequestToViewNameTranslator generates one from URI = path from servlet path without slashes and filename extension: resources/myfilename
BeanNameViewResolver try to get a View from context named resources/myfilename, seem that fails and chain to next ViewResolver
InternalResourceViewResolver return a JstlView pointing to jsp prefix + viewName + suffix = /WEB-INF/jsp/resources/myfilename.jsp
So BeanNameViewResolver seems that don't resolve the view and the return of InternalResourceViewResolver is the expected one.
What you want (I think)
You want to remove the filename from the default view name, not only the extension.
Implements a RequestToViewNameTranslator and declare it in the DispatcherServlet context with name viewNameTranslator.
For example:
public class StripFileNameViewNameTranslator extends DefaultRequestToViewNameTranslator {
#Override
protected String transformPath(String lookupPath) {
String path = super.transformPath(lookupPath);
return StringUtils.substringBeforeLast(path, "/");
}
}

Related

HttpSession setMaxInactiveInterval do not trigger Spring Security session SessionDestroyedEvent

I have a listener to set session timeout dynamically
public class DynamicSessionTimeoutHttpSessionListener implements HttpSessionListener{
#Override
public void sessionCreated(HttpSessionEvent event) {
long sessionTimeoutInMinute = ConfigEntryMgr.getInstance().getByKeyAsLong(ConfigEntryKeys.SESSION_TIMEOUT_IN_MINUTE);
event.getSession().setMaxInactiveInterval((int) sessionTimeoutInMinute * 60);
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
}
}
In spring security I do not allow concurrent session:
<beans:bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry" />
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="true" />
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</beans:bean>
<beans:bean
class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry" />
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
As a result nobody can login with a username that already is logged in.
The problem is that setMaxInactiveInterval does not destroy spring session.
Unless first user open the browser again and do an action, the servlet does not find out this session has expired to trigger SessionDestroyedEvent.
Now if the first user just close his browser, no body can login with this user forever, because Spring Security thinks somebody is still logged in with this username

Is it possible to using expression on Spring SecurityMetadataSource?

i want to manage url authorization by Database. So, i'm implement Security MetadataSource. It was perfect except cann't using expression.
below is my code and xml settings.
xml
<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" ref="securityMetadataSource" />
</beans:bean>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.access.vote.RoleVoter">
<beans:property name="rolePrefix" value="" />
</beans:bean>
</beans:list>
</beans:constructor-arg>
<beans:property name="allowIfAllAbstainDecisions" value="false" />
</beans:bean>
<beans:bean id="securityMetadataSource" class="my.package.CustomSecurityMetadataSource">
</beans:bean>
java
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
#Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
HttpServletRequest request = fi.getHttpRequest();
// TODO get url authorization from db and caching
String[] roles = new String[] { "ROLE_ANONYMOUS", "ROLE_USER"};
return SecurityConfig.createList(roles);
}
#Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
#Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
i want to using expression like hasAnyRole("ROLE_ADMIN", "ROLE_USER").
how can i use expression?

Spring batch-Circular reference error while using Java Beans but the application runs properly by using xml beans

Bean "delegateItemWriter" and "itemWriter" have cyclic calls to each other.
When I comment xml bean(which runs fine) and run by using java beans it gives me error as "Requested bean is currently in creation".
Can anyone help why this is happening with java beans only and not for xml beans?
Any help would be appreciated.
Batch Job defination:
<job id="fileToFileWithHeaderFooterJob" job-repository="jobRepository">
<step id="step">
<tasklet>
<chunk reader="itemReader" processor="itemProcessor" writer="itemWriter"
commit-interval="2">
<streams>
<stream ref="delegateItemWriter" />
</streams>
</chunk>
<listeners>
<listener ref="itemWriter" />
</listeners>
</tasklet>
</step>
</job>
If I comment below xml bean(delegateItemWriter) my application breaks and gives me error as Error creating bean with name 'delegateItemWriter': Requested bean is currently in creation: Is there an unresolvable circular reference?
<beans:bean id="delegateItemWriter"
class="org.springframework.batch.item.file.FlatFileItemWriter">
<beans:property name="resource" ref="outputFileResource" />
<beans:property name="shouldDeleteIfExists" value="true" />
<beans:property name="lineAggregator">
<beans:bean
class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<beans:property name="delimiter" value="," />
<beans:property name="fieldExtractor">
<beans:bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<beans:property name="names"
value="newId,newName,newDate,newParty,newPrice" />
</beans:bean>
</beans:property>
</beans:bean>
</beans:property>
<beans:property name="headerCallback" ref="headerCallback" />
<beans:property name="footerCallback" ref="itemWriter" />
</beans:bean>
Java Config:
#Bean
public FlatFileItemReader<Object> itemReader() {
FlatFileItemReader<Object> itemReader = new FlatFileItemReader<>();
DefaultLineMapper<Object> lineMapper = new DefaultLineMapper<>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setNames(new String[] {"dealId", "price", "name", "party", "Date"});
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(new TradeDataFieldSetMapper());
itemReader.setResource(new ClassPathResource("inputData.txt"));
itemReader.setLineMapper(lineMapper);
return itemReader;
}
#Bean
public SimpleItemProcessor itemProcessor() {
return new SimpleItemProcessor();
}
#Bean
public FileToFileFooterCallback itemWriter(final ItemWriter<TradeDataOutput> delegetItemWriter) {
FileToFileFooterCallback footerCallback = new FileToFileFooterCallback();
footerCallback.setDelegate(delegetItemWriter);
return footerCallback;
}
#Bean
public FlatFileItemWriter<TradeDataOutput> delegateItemWriter(final FileToFileFooterCallback itemWriter) {
FlatFileItemWriter<TradeDataOutput> writer = new FlatFileItemWriter<>();
LineAggregator<TradeDataOutput> delimitedLineAggregator = new DelimitedLineAggregator<>();
FieldExtractor<TradeDataOutput> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
String[] names = {"newID", "newName", "newDate", "newParty", "newPrice"};
((BeanWrapperFieldExtractor<TradeDataOutput>) beanWrapperFieldExtractor).setNames(names);
((DelimitedLineAggregator<TradeDataOutput>) delimitedLineAggregator).setDelimiter(",");
((DelimitedLineAggregator<TradeDataOutput>) delimitedLineAggregator).setFieldExtractor(beanWrapperFieldExtractor);
writer.setLineAggregator(delimitedLineAggregator);
writer.setResource(new FileSystemResource(
"batch/filetoFileWithHeaderFooterOutputFile.data"));
writer.setShouldDeleteIfExists(true);
writer.setHeaderCallback(new FileToFileHeaderCallback());
writer.setFooterCallback((FlatFileHeaderCallback) itemWriter);
return writer;
}

Conflicting beans of userDetailsService

I am working on a Spring-MVC application with spring-security and I have 2 different types of users who can login, one is from a personal account, and one is the group account.
So basically I want 2 daoAuthenticationMethods.
For both I have implemented the UserDetails and userDetailsService interface. After referring to the post on this I am trying to implement that approach.
The error I am getting is conflicting userDetailsService in the Service layer. I know I cannot use 2 userDetailsService, but if I put something else in the xml's property tab, I get unknown property error. Kindly check the configuration and please tell me what I might be doing wrong.
Error log :
Offending resource: ServletContext resource [/WEB-INF/spring/appServlet/security-applicationContext.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/spring/appServlet/servlet-context.xml]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'userDetailsService' for bean class [com.journaldev.spring.service.GroupLoginServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [com.journaldev.spring.service.LoginServiceImpl]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
Security-application-context.xml :
<!-- Global Security settings -->
<security:global-method-security pre-post-annotations="enabled" />
<security:http create-session="ifRequired" use-expressions="true" auto-config="true" disable-url-rewriting="true">
<security:form-login login-page="/" default-target-url="/canvas/list"
always-use-default-target="false" authentication-failure-url="/denied.jsp" />
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/**" filters="authenticationProcessingFilterForPersonal, authenticationProcessingFilterForGroup"/>
</security:filter-chain-map>
</bean>
<bean id="authenticationProcessingFilterForPersonal"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForPersonal"/>
<property name="filterProcessesUrl" value="/j_spring_security_check_for_person" />
</bean>
<bean id="authenticationProcessingFilterForGroup"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForGroup"/>
<property name="filterProcessesUrl" value="/j_spring_security_check_for_group"/>
</bean>
<bean id="authenticationManagerForPersonal" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref bean="LoginServiceImpl"/>
</property>
<property name="passwordEncoder" ref="encoder"/>
</bean>
</list>
</property>
</bean>
<bean id="authenticationManagerForGroup" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref bean="GroupLoginServiceImpl"/>
</property>
<property name="passwordEncoder" ref="encoder"/>
</bean>
</list>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="authenticationManagerForPersonal"/>
<security:authentication-provider ref="authenticationManagerForGroup"/>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
LoginServiceImpl :
// This method is for the personalAccount
#Transactional
#Service("userDetailsService")
public class LoginServiceImpl implements UserDetailsService{
#Autowired private PersonDAO personDAO;
#Autowired private Assembler assembler;
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_USER");
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
Person person = personDAO.findPersonByUsername(username.toLowerCase());
if(person == null) { throw new UsernameNotFoundException("Wrong username or password");}
return assembler.buildUserFromUserEntity(person);
}
}
GroupLoginServiceImpl :
#Transactional
#Service("userDetailsService") // I cannot change this, it throws me error when I change this or remove this
public class GroupLoginServiceImpl implements UserDetailsService {
#Autowired
private GroupMembersDAO groupMembersDAO;
#Autowired
private GroupAssembler groupAssembler;
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_GROUP");
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
GroupMembers groupMembers = groupMembersDAO.findMemberByUsername(username.toLowerCase());
if(groupMembers == null) { throw new UsernameNotFoundException("Wrong username or password");}
return groupAssembler.buildUserFromUserEntity(groupMembers);
}
}
I can post any other methods too if necessary. kindly let me know what to do. Any pointers are welcome. Thank you.
I think you have misunderstood how to write the XML. The first instance should be something like:
<property name="userDetailsService" ref="userDetailsService">
And the second:
<property name="userDetailsService" ref="groupDetailsService">

Spring-mvc validation error not being picked from property file

Using spring-mvc build in JSR303 bean validation and its working fine except for one issue, messages are not being picked from property file.
My Web-application is being created with maven and this is current structure
Main
-java
-resources
-bundles
-message.properties
-webapp
XML file
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basenames">
<beans:list>
<beans:value>bundles/messages</beans:value>
<beans:value>bundles/shipping</beans:value>
<beans:value>bundles/payment</beans:value>
</beans:list>
</beans:property>
</beans:bean>
--
validator
<beans:bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<beans:property name="validationMessageSource" ref="messageSource"/>
</beans:bean>
annotation-driven
<annotation-driven>
<message-converters>
<beans:bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
<beans:property name="supportedMediaTypes">
<beans:list>
<beans:value>image/jpeg</beans:value>
<beans:value>image/gif</beans:value>
<beans:value>image/png</beans:value>
</beans:list>
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>
Java File
#NotEmpty(message="{registration.firstName.invalid}")
public String getFirstName() {
return firstName;
}
Some how on my JSP page, I am getting these messages This field is required, not sure what is issue
My Data class is having following structure
PersistableCustomer extends SecuredCustomer
SecuredCustomer extends CustomerEntity
Even after passing message source to validator, its not picking up message from custom property file.
I am taking a wild guess here... usually JSR-303 message interpolator is taking messages from ValidationMessages.properties. If you want your validator to use Spring's message source, you need to configure it that way:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource" />
</bean>
<mvc:annotation-driven validator="validator" />

Resources