How do I Autowire some beans to be automatically injected with Spring MVC 3? - spring-mvc

OK, so we are learning Spring MVC 3. And we are a little new to IoC, DI, etc. We want to clean up a lot of our old legacy mistakes. :-)
We are really liking #Autowired for our user services, etc.
However, we now have an issue that we would like to solve with Autowiring.
Let's say we have a Login bean:
public class Login {
private String username;
private String email;
// getters/setters....
}
This bean should be used session wide. We want every controller to be able to access this single object.
Which I'm assuming we need in our application-config.xml
<bean id="login" class="com.example.models.Login" scope="session" />
Also, let's say we have another class as:
public class Employee {
private String firstName;
private String lastName;
private Login login;
public Employee(Login paLogin) {
this.login = paLogin;
}
}
And to put that in session:
<bean id="employee" class="com.example.models.Employee" scope="session" />
OK, later on in our application, we have an email notification service. That service needs to access the username and email from the Login bean AND information from the Employee bean. Granted I could access the login bean from session memory but this is just an example.
#Controller
public class EmailController {
#Autowired
Login login; // this should come from session memory automatically right??
#Autowired
Employee employee; // OK, this should also come from session memory. Which contains a reference of the login too. Correct?
// getters/setters....
public void sendEmails() {
// ....
String email = login.getEmail();
String firstName = employee.getFirstName();
// ....
}
}
I hope this makes sense. What we are really wanting to accomplish is reducing XML configs, reducing constant parameter passing, minimal annotations, etc.
Any help that could point me in the right direction would be appreciated.
Thanks!

Couple of things about the controller you have put up.
#Controller
public class EmailController {
#Autowired
Login login; // The container has to create a bean of type Login to autowire into EmailController
#Autowired
Employee employee; //same as above
// getters/setters....
}
If the container has to create a singleton bean on application startup, you have to mark the Login and Employee class with annotation #Component.
Even annotations like #Repository, #Service does this. You can have look at this answer for difference between these annotations.
So once you mark your classes with any of these annotations, singleton beans of respective type will be created on application startup. You will see something like this in your logs
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#6c811e18
And then a list of beans it has created. You can inject these beans to other beans. And these beans aren't stored in the session. But they are managed by the container itself.
You can do away with the xml bean definitions if your are using annotations like #Controller, #Component etc. Also you can avoid majority of your xml configuration files by using #Configuration. You can check here and here for examples.

Related

Running a task in background on jsf form submit

In my JSF application i have a process that takes to long to complete and i don't want that the user keeps waiting till its finish. I'm trying to implement some kind of 'fire and forget task' to run in background.
I'm doing it using an #Asynchronous method. This is the right approach?
My controller:
#ViewScoped
#Named
public class Controller implements Serializable {
private static final long serialVersionUID = -6252722069169270081L;
#Inject
private Record record;
#Inject
private Service service;
public void save() {
this.record.generateHash();
boolean alreadyExists = this.service.existsBy(this.record.getHash());
if (alreadyExists)
Messages.add(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "This record already exists"));
else {
this.service.save(this.record);
this.clearFields();
}
}
}
My service:
#Stateless
public class Service extends AbstractService<Record> {
private static final long serialVersionUID = -6327726420832825798L;
#Inject
private BeanManager beanManager;
#Override
public void save(Record record) {
super.save(record);
this.preProcess(record);
}
#Asynchronous
private void preProcess(Cd cd) {
// Long task running here ...
this.beanManager.fireEvent(cd);
}
}
But even with this approach the user keeps stuck at the page till the preProcess method finishes.
The problem here is that annotations that modify the behavior of EJBs (and CDI beans) are only applied when called by the "proxy" object that gets injected to appropriate injection points, like fields annotated with #EJB or #Inject.
This is because of how the containers implement the functionality that modifies the behavior. The object that the container injects to clients of EJBs (and normal-scoped CDI beans) is actually a proxy that knows how to call the correct instance of the target bean (e.g. the correct instance of e #RequestScoped bean). The proxy also implements the extra behaviors, like #Transactional or #Asynchronous. Calling the method through this bypasses the proxy functionalities! For this reason placing these annotations on non-public methods is effectively a NO-OP!
A non-exclusive list of solutions:
Move preProcess() to a different EJB, make it public and keep the #Asynchronous annotation
Make preProcess() public and call it from the Controller
If the computation is truly private to the Service and exposing it would break design, and ou don't mind doing a bit more manual work, you can always run async tasks from the container-provided ManagedExecutorService:
#Resource
private ManagedExecutorService managedExecutorService;
Pay attention to the semantics of the thread that executes your code - more specifically to what context values are propagated and what not! Well, you have to pay attention to that for #Asynchronous methods too!

Spring security Authentication parameter in #Controller handler method [duplicate]

I have a Spring MVC web app which uses Spring Security. I want to know the username of the currently logged in user. I'm using the code snippet given below . Is this the accepted way?
I don't like having a call to a static method inside this controller - that defeats the whole purpose of Spring, IMHO. Is there a way to configure the app to have the current SecurityContext, or current Authentication, injected instead?
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request...) {
final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
...
}
If you are using Spring 3, the easiest way is:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request, Principal principal) {
final String currentUser = principal.getName();
}
A lot has changed in the Spring world since this question was answered. Spring has simplified getting the current user in a controller. For other beans, Spring has adopted the suggestions of the author and simplified the injection of 'SecurityContextHolder'. More details are in the comments.
This is the solution I've ended up going with. Instead of using SecurityContextHolder in my controller, I want to inject something which uses SecurityContextHolder under the hood but abstracts away that singleton-like class from my code. I've found no way to do this other than rolling my own interface, like so:
public interface SecurityContextFacade {
SecurityContext getContext();
void setContext(SecurityContext securityContext);
}
Now, my controller (or whatever POJO) would look like this:
public class FooController {
private final SecurityContextFacade securityContextFacade;
public FooController(SecurityContextFacade securityContextFacade) {
this.securityContextFacade = securityContextFacade;
}
public void doSomething(){
SecurityContext context = securityContextFacade.getContext();
// do something w/ context
}
}
And, because of the interface being a point of decoupling, unit testing is straightforward. In this example I use Mockito:
public class FooControllerTest {
private FooController controller;
private SecurityContextFacade mockSecurityContextFacade;
private SecurityContext mockSecurityContext;
#Before
public void setUp() throws Exception {
mockSecurityContextFacade = mock(SecurityContextFacade.class);
mockSecurityContext = mock(SecurityContext.class);
stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
controller = new FooController(mockSecurityContextFacade);
}
#Test
public void testDoSomething() {
controller.doSomething();
verify(mockSecurityContextFacade).getContext();
}
}
The default implementation of the interface looks like this:
public class SecurityContextHolderFacade implements SecurityContextFacade {
public SecurityContext getContext() {
return SecurityContextHolder.getContext();
}
public void setContext(SecurityContext securityContext) {
SecurityContextHolder.setContext(securityContext);
}
}
And, finally, the production Spring config looks like this:
<bean id="myController" class="com.foo.FooController">
...
<constructor-arg index="1">
<bean class="com.foo.SecurityContextHolderFacade">
</constructor-arg>
</bean>
It seems more than a little silly that Spring, a dependency injection container of all things, has not supplied a way to inject something similar. I understand SecurityContextHolder was inherited from acegi, but still. The thing is, they're so close - if only SecurityContextHolder had a getter to get the underlying SecurityContextHolderStrategy instance (which is an interface), you could inject that. In fact, I even opened a Jira issue to that effect.
One last thing - I've just substantially changed the answer I had here before. Check the history if you're curious but, as a coworker pointed out to me, my previous answer would not work in a multi-threaded environment. The underlying SecurityContextHolderStrategy used by SecurityContextHolder is, by default, an instance of ThreadLocalSecurityContextHolderStrategy, which stores SecurityContexts in a ThreadLocal. Therefore, it is not necessarily a good idea to inject the SecurityContext directly into a bean at initialization time - it may need to be retrieved from the ThreadLocal each time, in a multi-threaded environment, so the correct one is retrieved.
I agree that having to query the SecurityContext for the current user stinks, it seems a very un-Spring way to handle this problem.
I wrote a static "helper" class to deal with this problem; it's dirty in that it's a global and static method, but I figured this way if we change anything related to Security, at least I only have to change the details in one place:
/**
* Returns the domain User object for the currently logged in user, or null
* if no User is logged in.
*
* #return User object for the currently logged in user, or null if no User
* is logged in.
*/
public static User getCurrentUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal()
if (principal instanceof MyUserDetails) return ((MyUserDetails) principal).getUser();
// principal object is either null or represents anonymous user -
// neither of which our domain User object can represent - so return null
return null;
}
/**
* Utility method to determine if the current user is logged in /
* authenticated.
* <p>
* Equivalent of calling:
* <p>
* <code>getCurrentUser() != null</code>
*
* #return if user is logged in
*/
public static boolean isLoggedIn() {
return getCurrentUser() != null;
}
To make it just show up in your JSP pages, you can use the Spring Security Tag Lib:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html
To use any of the tags, you must have the security taglib declared in your JSP:
<%# taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
Then in a jsp page do something like this:
<security:authorize access="isAuthenticated()">
logged in as <security:authentication property="principal.username" />
</security:authorize>
<security:authorize access="! isAuthenticated()">
not logged in
</security:authorize>
NOTE: As mentioned in the comments by #SBerg413, you'll need to add
use-expressions="true"
to the "http" tag in the security.xml config for this to work.
If you are using Spring Security ver >= 3.2, you can use the #AuthenticationPrincipal annotation:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(#AuthenticationPrincipal CustomUser currentUser, HttpServletRequest request) {
String currentUsername = currentUser.getUsername();
// ...
}
Here, CustomUser is a custom object that implements UserDetails that is returned by a custom UserDetailsService.
More information can be found in the #AuthenticationPrincipal chapter of the Spring Security reference docs.
I get authenticated user by
HttpServletRequest.getUserPrincipal();
Example:
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.support.RequestContext;
import foo.Form;
#Controller
#RequestMapping(value="/welcome")
public class IndexController {
#RequestMapping(method=RequestMethod.GET)
public String getCreateForm(Model model, HttpServletRequest request) {
if(request.getUserPrincipal() != null) {
String loginName = request.getUserPrincipal().getName();
System.out.println("loginName : " + loginName );
}
model.addAttribute("form", new Form());
return "welcome";
}
}
In Spring 3+ you have have following options.
Option 1 :
#RequestMapping(method = RequestMethod.GET)
public String currentUserNameByPrincipal(Principal principal) {
return principal.getName();
}
Option 2 :
#RequestMapping(method = RequestMethod.GET)
public String currentUserNameByAuthentication(Authentication authentication) {
return authentication.getName();
}
Option 3:
#RequestMapping(method = RequestMethod.GET)
public String currentUserByHTTPRequest(HttpServletRequest request) {
return request.getUserPrincipal().getName();
}
Option 4 : Fancy one : Check this out for more details
public ModelAndView someRequestHandler(#ActiveUser User activeUser) {
...
}
I would just do this:
request.getRemoteUser();
Yes, statics are generally bad - generally, but in this case, the static is the most secure code you can write. Since the security context associates a Principal with the currently running thread, the most secure code would access the static from the thread as directly as possible. Hiding the access behind a wrapper class that is injected provides an attacker with more points to attack. They wouldn't need access to the code (which they would have a hard time changing if the jar was signed), they just need a way to override the configuration, which can be done at runtime or slipping some XML onto the classpath. Even using annotation injection in the signed code would be overridable with external XML. Such XML could inject the running system with a rogue principal. This is probably why Spring is doing something so un-Spring-like in this case.
For the last Spring MVC app I wrote, I didn't inject the SecurityContext holder, but I did have a base controller that I had two utility methods related to this ... isAuthenticated() & getUsername(). Internally they do the static method call you described.
At least then it's only in once place if you need to later refactor.
You could use Spring AOP aproach.
For example if you have some service, that needs to know current principal. You could introduce custom annotation i.e. #Principal , which indicate that this Service should be principal dependent.
public class SomeService {
private String principal;
#Principal
public setPrincipal(String principal){
this.principal=principal;
}
}
Then in your advice, which I think needs to extend MethodBeforeAdvice, check that particular service has #Principal annotation and inject Principal name, or set it to 'ANONYMOUS' instead.
The only problem is that even after authenticating with Spring Security, the user/principal bean doesn't exist in the container, so dependency-injecting it will be difficult. Before we used Spring Security we would create a session-scoped bean that had the current Principal, inject that into an "AuthService" and then inject that Service into most of the other services in the Application. So those Services would simply call authService.getCurrentUser() to get the object. If you have a place in your code where you get a reference to the same Principal in the session, you can simply set it as a property on your session-scoped bean.
The best solution if you are using Spring 3 and need the authenticated principal in your controller is to do something like this:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
#Controller
public class KnoteController {
#RequestMapping(method = RequestMethod.GET)
public java.lang.String list(Model uiModel, UsernamePasswordAuthenticationToken authToken) {
if (authToken instanceof UsernamePasswordAuthenticationToken) {
user = (User) authToken.getPrincipal();
}
...
}
Try this
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
String userName = authentication.getName();
I am using the #AuthenticationPrincipal annotation in #Controller classes as well as in #ControllerAdvicer annotated ones. Ex.:
#ControllerAdvice
public class ControllerAdvicer
{
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAdvicer.class);
#ModelAttribute("userActive")
public UserActive currentUser(#AuthenticationPrincipal UserActive currentUser)
{
return currentUser;
}
}
Where UserActive is the class i use for logged users services, and extends from org.springframework.security.core.userdetails.User. Something like:
public class UserActive extends org.springframework.security.core.userdetails.User
{
private final User user;
public UserActive(User user)
{
super(user.getUsername(), user.getPasswordHash(), user.getGrantedAuthorities());
this.user = user;
}
//More functions
}
Really easy.
Define Principal as a dependency in your controller method and spring will inject the current authenticated user in your method at invocation.
I like to share my way of supporting user details on freemarker page.
Everything is very simple and working perfectly!
You just have to place Authentication rerequest on default-target-url (page after form-login)
This is my Controler method for that page:
#RequestMapping(value = "/monitoring", method = RequestMethod.GET)
public ModelAndView getMonitoringPage(Model model, final HttpServletRequest request) {
showRequestLog("monitoring");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String userName = authentication.getName();
//create a new session
HttpSession session = request.getSession(true);
session.setAttribute("username", userName);
return new ModelAndView(catalogPath + "monitoring");
}
And this is my ftl code:
<#security.authorize ifAnyGranted="ROLE_ADMIN, ROLE_USER">
<p style="padding-right: 20px;">Logged in as ${username!"Anonymous" }</p>
</#security.authorize>
And that's it, username will appear on every page after authorisation.

Which component should handle DB access in the Java EE stack with regards to the MVC pattern

I'm fairly new to both Java EE and MVC. I have to develope a web application using Servlet, JSP, JB and EJB. As most applications mine too needs to interact with a RDBMS.
A friend of mine sent me a wep App he developed in which he has a
Serializable DbManager class
in which a
private transient Connection
exists as a member variable.
In all his servlets in which he needs DB access he has a DbManager variable. It is instantiate in the init method of the servlet and it is retrived like this :
this.manager = (DbManager)super.getServletContext().getAttribute("dbmanager");
All the queries are implemented as public methods of the DbManager Class.
I was wondering if this is a good way to implement such needs or if there is a better way to handle Db access and queries execution. I tought of implementing business logic and thus DB access as public methods in my EJBs.
Thanks for any help!
Homemade DbManager style classes are redundant when you are living in a JavaEE environment. You can make use of JPA for performing all your database queries from a stateless session bean that forms the "controller" part of your MVC architecture:
#Stateless
public class OrderController {
#PersistenceContext
private EntityManager em;
public void addNewOrder(Order order) {
em.persist(order)
}
public List<Order> findAllOrders() {
TypedQuery<Order> findAllOrdersQuery = em.createQuery("select o from Order o", Order.class);
return findAllOrdersQuery.list();
// In practice you would add pagination to this.
// It's not practical to return a million orders to your view.
}
...
}
This stateless EJB manages all transactions on your behalf, so you don't normally need to be concerned with beginning, committing and/or rolling back transactions.
The Order class is a component of your "model":
#Entity
public class Order {
#Id
private long id;
#Column
private String orderNumber;
#Column
private String description;
// other attributes
...
Order() { }
public Order(String orderNumber, String description) {
this.orderNumber = orderNumber;
this.description = description;
}
// setters and getters
...
// you must also override equals() and hashCode()
}
You will see many examples where developers introduce a so called DAO layer into their controller, but this is considered redundant as the EntityManager essentially satisfies that contract.

How do you secure SpringBoot / Spring-Data Rest so user can only access his own entities

I'm using Spring-Data/Rest (http://docs.spring.io/spring-data/rest/docs/current/reference/html/) with Spring Boot and basic Spring Security.
I have the following entities.
Items
-->ID
User
--> ID
--> List<Items> items
Currently with spring rest, any user can see /items/1,2,3,4,5
I want only to allow users, to only see their own items.
Is this achievable without having to code a custom controller ?
I think multitenancy on JPA level could be a nice transparent approach to spearating the data a user can see. Please see my answer here for details:
https://stackoverflow.com/a/33648305/5371736
Use Spring Security and Spring Security Data:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>
Enable JPA Auditing:
#SpringBootApplication
#EnableJpaAuditing
public class SdrRlsApplication {
public static void main(String[] args) {
SpringApplication.run(SdrRlsApplication.class, args);
}
}
Add an "owner" field (or what have you) to your entities:
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Getter
public class Foo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String owner;
private String name;
}
Add Spring Security SPeL expressions to your Repositories:
public interface FooRepository extends PagingAndSortingRepository<Foo, Long> {
#Query(
value="select f from Foo f where f.owner=?#{principal.username}",
countQuery="select count(f) from Foo f where f.owner=?#{principal.username}"
)
Page<Foo> findAll(Pageable pageable);
}
Yes,you could.
For this what you could do is assign each User a particular role.For example ,in your case,assign user who owns the items as role column ADMIN and all others ANONYMOUS or USER,you pick.After this, using spring security you could make the request fail for the users having ANONYMOUS or USER role for the items URL and only allow users with ADMIN role to view the items.
Now,this could be achieved via spring security in multiple ways :
1.Using #PreAuthorize tags for individual controller methods and testing roles ADMIN/USER/..
But,i guess ,you do not want to modify the controller as such drastically.
The short manual way,which is,to create authentication object into context holder and use spring boot security config,such as below,for example :
#Order(1)
public class UserFilter extends Filter {
#Autowired
UserService userService;
...
UserObject userObject = userService.getUser(arg..);
List<GrantedAuthority> grantedAuthorityList = new ArrayList<GrantedAuthority>();
grantedAuthorityList.add( new SimpleGrantedAuthority((userObject.getRoleName()));//Either ROLE_ADMIN or ROLE_USER
Authentication authentication = new PreAuthenticatedAuthenticationToken(userObject.getId(), new Object(), grantedAuthorityList);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request,response);
...
}
And the security configuration class :
#Configuration
#EnableWebSecurity
public class SecurityConfigREST extends WebSecurityConfigurerAdapter {
SecurityConfigREST(){
super(true);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
PreAuthenticatedAuthenticationProvider pap=new PreAuthenticatedAuthenticationProvider();
pap.setPreAuthenticatedUserDetailsService(new PreAuthenticatedGrantedAuthoritiesUserDetailsService());
auth.authenticationProvider(pap);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.regexMatchers("^/items.*$").hasAuthority("ROLE_ADMIN") //The role which should have access to /items/1,2.. URL
.anyRequest().authenticated();
}
}
Use UserDetailsService in the security config above and load the user and its role in a preauthenticated authentication provider.
Refer : http://docs.spring.io/autorepo/docs/spring-security/3.2.2.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html
Having said all that ,its also a good design not to pass items (1,2,3) numbers via URL,as could lead to potential issues later,so use GET and pass JSON request body to it such as :
/items RequestMethod.GET
{
"itemList" : [1,2,3,4,5]
}
Hope that helps.

How can I use same EJB in two different CDI beans and retrieve the values set from one bean into the another?

I have a stateful session bean where a list is maintained:
#Stateful
public class CartDAO{
private List<ShoppingCart> tempCart;
public void add(ShoppingCart shoppingCart){
tempCart.add(shoppingCart);
}
public List<ShoppingCart> getCart(){
return tempCart;
}
#PostConstruct
public void init(){
tempCart = new ArrayList<>();
}
}
Controller1 to add to the cart:
#Named
#SessionScoped
public class Controller1 implements Serializable {
#EJB
CartDAO cartDao;
public String addToShoppingCart() {
cartDao.add(shoppingCart);
}
}
Now, i want to ask you could i get the added items to the list from another cart?
#Named
#SessionScoped
public class Controller2 implements Serializable {
#EJB
CartDAO cartDao;
public String getShoppingCart() {
System.out.println(cartDao.getCart());//returns null
}
}
Obviously the above code returns null.
How do I retrieve the list from another controller. Any help will be much appreciated.
I don't see any obvious mistake here (are you sure that you don't call Controller2#getShoppingCart() before adding any items do your CartDAO?) but here are couple of my notions
you should have your CartDAO implement some interface or make it #LocalBean
all stateful beans should have method annotated with #Remove so you can clean the resources used in the bean (close datasources and son) and bean will be removed from the memory after this call
now it's recommended to use #Inject everywhere instead of #EJB, it's the same (you have to use #EJB only when you inject remote beans)
And also one point, if the System.out.println(cartDao.getCart()); returns null than it means the #PostConstruct haven't been called which is strange. Can you provide some more info about container and your environment?Also show us imports, this is big source of mistakes.

Resources