I am working on a Spring-MVC project where I am using Spring-Security for authentication and other security features. Now the Project is divided into 2 parts, one is for personal login and another is group login.
For both of them, I use different database tables. But Java classes for both the tables have one instance of UserDetails and userDetailsService implemented.
Now when the user logs-in either from the personal account or from group account, I would like to extract the currently logged in users object from either of the class. This way, I would know if its a group user logged in or a personal account user logged in. Kindly let me know what should I do?
security-application-context.xml :
<security:http create-session="ifRequired" use-expressions="true"
entry-point-ref="loginUrlAuthenticationEntryPoint"
auto-config="false" disable-url-rewriting="true">
<security:logout logout-success-url="/" delete-cookies="JSESSIONID"
invalidate-session="true" logout-url="/j_spring_security_logout"/>
<security:custom-filter ref="CustomUsernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
</security:http>
<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.do?error"/>
</bean>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.do"/>
</bean>
<bean id="authenticationManagerForPersonal" class="com.journaldev.spring.utility.CustomDAOAuthenticationProvider">
<constructor-arg index="0" value="org.springframework.security.authentication.UsernamePasswordAuthenticationToken"/>
<property name="userDetailsService" ref="LoginServiceImpl"/>
<property name="passwordEncoder" ref="encoder"/>
</bean>
<bean id="authenticationManagerForGroup" class="com.journaldev.spring.utility.CustomDAOAuthenticationProvider">
<constructor-arg index="0" value="com.journaldev.spring.utility.CustomUsernamePasswordAuthenticationToken"/>
<property name="userDetailsService" ref="GroupLoginServiceImpl"/>
<property name="passwordEncoder" ref="encoder"/>
</bean>
<bean id="CustomUsernamePasswordAuthenticationFilter" class="com.journaldev.spring.utility.CustomUsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="redirectRoleStrategy"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="authenticationManagerForPersonal"/>
<security:authentication-provider ref="authenticationManagerForGroup"/>
</security:authentication-manager>
<bean id="redirectRoleStrategy" class="com.journaldev.spring.utility.RoleBasedAuthenticationSuccessHandler">
<property name="roleUrlMap">
<map>
<entry key="ROLE_USER" value="/person.do"/>
<entry key="ROLE_GROUP" value="/group.do"/>
</map>
</property>
</bean>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
Person.Java (Personal accounts model class) :
#Entity
#Table(name="person")
public class Person implements UserDetails{
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "person_seq_gen")
#SequenceGenerator(name = "person_seq_gen",sequenceName = "person_seq")
private int id;
// other values
}
GroupMember.java (Group Account members model)
#Entity
#Table(name="groupmembers")
public class GroupMembers implements UserDetails {
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_GROUP");
#Id
#Column(name="memberid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "groupmembers_seq_gen")
#SequenceGenerator(name = "groupmembers_seq_gen",sequenceName = "groupmembers_seq")
private Long memberid;
// Other values
}
Edit :
This is how I retrieve the current user, but I cannot find how to check to which object it is, I can get an Object of UserDetails, but as both methods are implementing UserDetails, I cannot tell which one it is.
#Override
public Person getCurrentlyAuthenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication == null){
return null;
} else {
return personDAO.findPersonByUsername(authentication.getName());
}
}
I hope this should be simple.
You have two UserDetails objects User1 and User2, suppose User1 is of the Person class and User2 is of GroupPerson.
You can get theUserDetails Object as you stated, then all you need to do is to check if the object is instance of Person or GroupMembers.
You can do it using instanceof like the following
if(userObject instanceof Person){
// DO Stuff
}
else if(userObject instanceof GroupMembers){
// Do Stuff
}
Here your userObject can be an object of either Person or GroupMember
Related
When I use redisCacheManager to put something, it throws an exception "Invalidated object not currently part of this pool". But when I set the usePool to false, it can work. I think this is a Multi-threaded case. But I don't know why the spring-data-redis's annotation can work.
<code>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserServiceImpl userService = applicationContext.getBean(UserServiceImpl.class);
RedisCacheManager redisCacheManager = applicationContext.getBean(RedisCacheManager.class);
redisCacheManager.getCache("cacheName").put("key","value");
<cache:annotation-driven ></cache:annotation-driven>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"/>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
</bean>
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate"/>
</code>
My requirement is to redirection between two different apps in different JVMs. And also transfer data between the two. I tried using Flash Attributes, but in the controller, the attributes are null. I tried creating an interceptor also, but even there the flash attributes are null. Can anyone help me on how to pass attributes between two different applications?
Here is my code:
poc1 - calling application
dispatcher-servlet.xml
<context:component-scan base-package="controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean name="flashMapManager" class="org.springframework.web.servlet.support.SessionFlashMapManager" />
<mvc:annotation-driven />
</beans>
Controller.java
#RequestMapping(value = "add", method = RequestMethod.POST)
public String add(#ModelAttribute("customer") Customer customer,
final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("customer", customer);
redirectAttributes.addFlashAttribute("message", "Added successfully.");
return "redirect:http://localhost:8080/poc2";
}
poc2 - called application
dispatcher-servlet.xml
<context:component-scan base-package="controller" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean name="flashMapManager"
class="org.springframework.web.servlet.support.SessionFlashMapManager" />
<!-- <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors"> <list> <ref bean="requestInterceptor" /> </list>
</property> </bean> -->
<bean id="requestInterceptor" class="RequestInterceptor" />
<mvc:annotation-driven />
<mvc:interceptors>
<ref bean="requestInterceptor" />
</mvc:interceptors>
</beans>
Controller.java
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(Model model, HttpServletRequest request,
HttpSession session) {
Map<String, ?> inputFlashMap = RequestContextUtils
.getInputFlashMap(request);
Customer cust1 = (Customer) model.asMap().get("customer");
Customer cust = (Customer) inputFlashMap.get("customer");
ModelAndView modelMap = new ModelAndView("showCustomer");
System.out.println("Calling controller");
return modelMap;
}
you can use this,
Using just redirectAttributes.addFlashAttribute(...) -> "redirect:..." worked as well, didn't have to "reinsert" the model attribute.
I'm using Spring 3.2 and my Spring MVC controller generate JSON data (with jackson-databind-2.2.0). I would like to customize my JSON root name with #JsonRootName (com.fasterxml.jackson.annotation.JsonRootName) annotation, however, I could not figure out how to enable it with Spring configuration.
#JsonRootName("rootNameTest")
public class MyModel {
private String prop;
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
}
Here's my settings in sevlet-context.xml
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.ParameterContentNegotiationStrategy">
<constructor-arg>
<map>
<entry key="json" value="application/json"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</list>
</property>
</bean>
Please help. Thanks.
Setbelow in com.fasterxml.jackson.databind.ObjectMapper
om.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
om.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
this may be done by extending above Class with your custom and inject in org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
I am trying to enhance my spring-enabled web-app's security using Apache Shiro and am thus configuring filterchain definitions into a spring-configured file.
How do i achieve the equivalent of
#Controller
#RequestMapping("/mywebapp")
// #RequiresAuthentication (is this possible ? wish i could do this !)
public class MyWebAppController {
#RequiresRoles(value={"Role1","Role2","Role3"},logical=Logical.OR)
#RequestMapping(value="/home", method = RequestMethod.GET)
public String home() { return .. }
and my spring-config file contains this :
assume that my dispatcherservlet is mapped to /rest/*
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/rest/secure/windowslogin"/>
<property name="successUrl" value="/mywebapp/rest/menu"/>
<property name="unauthorizedUrl" value="/mywebapp/rest/unauthorized"/>
<property name="filters">
<util:map>
<entry key="anon">
<bean class="org.apache.shiro.web.filter.authc.AnonymousFilter"/>
</entry>
<entry key="authc">
<!-- why is this not invoked ? -->
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter">
</bean>
</entry>
<entry key="roles">
<bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"/>
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/rest/secure/** = anon
/rest/mywebapp/** = authc, roles[Role1,Role2,Role3]
</value>
</property>
</bean>
In the code above i need a logical.OR kind of mapping to the /rest/mywebapp/** using the roles mentioned. This is possible via shiro annotations and it works but rather than specifying at every method i would rather handle it here (since i dont think shiro supports class level annotations yet ?) .
Is this possible ?
Also on a side note why is the authc filter not invoked ?
( for now we assume that the windows login can serve as authentication, using shiro only for authorization )
home page = meta refresh to /rest/secure/windowslogin/
if within intranet -> login ...
else /rest/secure/login ... login page.
Is it because the loginurl is different ? How do i circumvent this ? Note that my realm's getAuthorizationInfo is invoked though using the roles[ .. ] part specified in the config file.. but i was assuming that there should be a check to see if the request is 'authc' ? (which probably means that the filter is invoked and SubjectUtils.getSubject() is checked for authentication). Am i missing something in the flow or configuration ?
This is how shiro-security.xml looks like.
<bean id="customFilter1" class="com.pkg.RolesAuthorizationFilter">
<property name="roles" value="ROLE1,ROLE3,ROLE5"></property>
</bean>
<bean id="customFilter2" class="com.pkg.RolesAuthorizationFilter">
<property name="roles" value="ROLE1,ROLE2,ROLE5,ROLE6"></property>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/home" />
<property name="unauthorizedUrl" value="/unauthorized" />
<property name="filters">
<util:map>
<entry key="authc">
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/resources/** = anon
/login = anon
/logout = authc
/unauthorized = authc
/someurl/** = customFilter2
/** = customFilter1
</value>
</property>
</bean>
And this is RolesAuthorizationFilter class
package com.pkg;
import java.util.Arrays;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
public class RolesAuthorizationFilter extends AuthorizationFilter {
protected Logger logger = Logger.getLogger(this.getClass()
.getCanonicalName());
private String[] roles;
#Override
protected boolean isAccessAllowed(ServletRequest request,
ServletResponse response, Object mappedValue) throws Exception {
logger.info("= Roles = " + Arrays.toString(roles));
Subject subject = getSubject(request, response);
boolean allowAccess = false;
for (String role : roles) {
if (subject.hasRole(role)) {
logger.info("Authenticated role " + role);
allowAccess = true;
break;
}
}
return allowAccess;
}
public void setRoles(String[] roles) {
this.roles = roles;
}
}
I;m trying to create RSS feeds for my web site. I follow the tutorial from mkyong (http://www.mkyong.com/spring-mvc/spring-3-mvc-and-rss-feed-example/) which was quite useful. According to this tutorial i create a model class and the following class
public class CustomRssViewer extends AbstractRssFeedView{
#Override
protected void buildFeedMetadata(){
//some code
}
#Override
protected List<Item> buildFeedItems(){
//some code
}
}
And finally the controller class
#Controller
public class RssController {
#RequestMapping(value="/rssfeed", method = RequestMethod.GET)
public ModelAndView getFeedInRss() {
//set the RSS content
ModelAndView mav = new ModelAndView();
mav.setViewName("rssViewer");
mav.addObject("feedContent", items);
return mav;
}
}
According to the tutorial the View rssViewer belongs the class CustomRssViewer , so i need to write it at the dispatcher servlet the following lines of code:
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="rssViewer" class="com.mkyong.common.rss.CustomRssViewer" />
My problem is that i'm using apache tiles. So the rssViewer can not be recognised as i didn't enhanced it to the tiles definition. And i really don't know how can i do this. For example i need to write something as the following:
<definition name="rssViewer" template="?">
<put-attribute name="title" value=""/>
<put-attribute name="content" value=""/>
</definition>
At the template i don't know what to declare as well as at the put-attribute.Because until now at the template i use to declare the direction that a specific jsp exists. Something like this:
template="/WEB-INF/pages/mypage.jsp"
And also at the view-properties i don't know what should i declare.
Thanks in advance for any comment or response.
You should use a ContentNegotiatingViewResolver in conjuction with that example's BeanNameViewResolver. Just declare the order property of your already existing BeanNameViewResolver to be 1, and set the order property of the new ContentNegotiatingViewResolver to 0.
You should then configure the ContentNegotiatingViewResolver to use the appropriate View for RSS, and set the media type for RSS.
Here is an example from the Spring Docs:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
Note, they are using atom, not RSS, but the idea is the same. Also they do not set the order (which you should do).