Play Framework: Using JPA entityManager in Interceptor Action class - java

I am using #With(Action.class) annotation to intercept the calls to specific controller/actions. I am trying to retrieve the session from database on in the interceptor function; however the JPA helper class is not available in the Action.class interceptor method "call".
Can someone please guide on how to retrieve database entities in the interceptor functions?
Thanks.
Interceptor class:
public class SecuredAction extends Simple {
public SecuredAction() {
// TODO Auto-generated constructor stub
}
#Override
public Promise<Result> call(Context ctx) throws Throwable {
// check isContactVerified/isEmailVerified
String sid = getSidFromCookie(ctx);
if (sid != null) {
Session appSession = (Session) JPA.em().createNamedQuery("Session.findBySessionId").getSingleResult();
User user = appSession.getUserId();
if (user != null) {
ctx.args.put("user", user);
return delegate.call(ctx);
}
}
Result unauthorized = Results.unauthorized("Invalid Session");
return F.Promise.pure(unauthorized);
}
private String getSidFromCookie(Http.Context ctx) {
return ctx.session().get(AppConstants.COOKIE_USER_SESSIONID);
}
}
Error:
[RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with #play.db.jpa.Transactional]

Wrap body of you action with JPA.withTransaction:
return JPA.withTransaction(
"default",
false, () -> {
String sid = getSidFromCookie(ctx);
if (sid != null) {
Session appSession = (Session) JPA.em().createNamedQuery("Session.findBySessionId").getSingleResult();
User user = appSession.getUserId();
if (user != null) {
ctx.args.put("user", user);
return delegate.call(ctx);
}
}
Result unauthorized = Results.unauthorized("Invalid Session");
return F.Promise.pure(unauthorized);
}
);
And do not annotate method with #Transactional if you annotated it with #With(SecuredAction.class).

Related

getting authenticated user inside the configuration class in Spring

I am using Spring Security to authenticate users. I need to resolve which user has authenticated in my ApplicationConfiguration to provide the correct data, but for some reason, the following code returns null:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
EDIT:
I basically want to inject a service into a controller. (PackagesBaseService)
This service is abstract, so in my bean definition (In configuration class) I need to resolve if PackagesBaseService is an instance of TablePackagesService or DeskPackagesService. This is based on which user is authenticated (this requirement cannot be changed).
I understand I could just test the Authenticated user even in my controller and instantiate my service there, but I would like to avoid that.
I am able though to retrieve the Auth user using this same from anywhere else.
Why I can't use this from a configuration file? Does it have something with the order that the beans are loaded?
How can I solve this?
Implementation:
Configuration:
#Bean
public PackagesBaseService packagesBaseService()
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)) {
if (authentication.getName() == env.getProperty("tableFactory.username")) {
return new TablePackagesService();
}
if (authentication.getName() == env.getProperty("deskFactory.username")) {
return new DeskPackagesService();
}
// thrown Exception
}
// thrown Exception
}
Controller:
#Autowired
PackagesBaseService packagesService;
public MultiPackagesResponse data(#RequestParam("fromId") int fromId)
{
MultiPackagesResponse response = packagesService.getPackages(fromId);
return response;
}
You need to go with a factory to be able to use the user context. This COULD look like this:
Define a Factory bean:
#Service
public class PackageBaseServiceFactory {
public final HashMap < String,
PackageBaseService > packageBaseServiceCache = new HashMap();
public PackageBaseService getPackageService() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)) {
PackageBaseService packageBaseService = packageBaseServiceCache.get(authentication.getName());
if (packageBaseService == null) {
packageBaseService = initPackagesBaseService(authentication.getName());
}
return packageBaseService;
}
}
private PackageBaseService initPackagesBaseService(String authenticationName) {
PackageBaseService packageBaseService;
if (authenticationName == env.getProperty("tableFactory.username")) {
packageBaseService = new TablePackagesService();
} else if (authenticationName == env.getProperty("deskFactory.username")) {
packageBaseService = new DeskPackagesService();
} else {
throw new IllegalStateException(); //or whatever you do
}
return packageBaseServiceCache.put(authenticationName, packageBaseService);
}
}
and used it this way
#Autowired
PackageBaseServiceFactory packageBaseServiceFactory;
public MultiPackagesResponse data( # RequestParam("fromId")int fromId) {
MultiPackagesResponse response = packageBaseServiceFactory.getPackageService().getPackages(fromId);
return response;
}

How to bind the session to the User object using jersey

I am trying to create login function and I want to save in the session specific data to use in future requests of the user is it possible?
In the loginUser, first if is always false even if the user already logged
and same in the updatePassword .
I need to save the attribute from the function loginUserToSession. Any idea why it doesn't work ?
here is my code
Resource
#Path("/logIn")
#Singleton
public class UserResource extends baseResource<UserDao, UserEntity>
{
#Path("/authenticateUser")
#GET
#UnitOfWork
public String loginUser(#Context HttpServletRequest req #QueryParam("callback") String callback, #QueryParam("loginInfo") LoginInfo loginInfo) throws JsonProcessingException
{
if(SessionManager.isUserConnected(req))
{
return ResourceResponse.getResourceJsonString("null", callback, "true", ErrorMessageEnum.SUCCESS);
}
String userName = loginInfo.username;
String plainTextPassword = loginInfo.password;
UserEntity user = objectDao.logIn(userName, plainTextPassword);
if(user != null)
{
SessionManager.loginUserToSession(req, user.getUserId(), userName);
return ResourceResponse.getResourceJsonString(user.getUserStatus(), callback, "true", ErrorMessageEnum.SUCCESS);
}
return ResourceResponse.getResourceJsonString("null", callback, "false", ErrorMessageEnum.LOGIN_FAILED);
}
#Path("/updatePassword")
#GET
#UnitOfWork
public String updatePassword(#Context HttpServletRequest req, #QueryParam("callback") String callback, #QueryParam("oldPwd") String oldPwd, #QueryParam("newPwd") String newPwd) throws JsonProcessingException
{
if(SessionManager.isUserConnected(req))
{
short userId = SessionManager.getUserId(req);
ObjectDaoResponse res = objectDao.updatePassword(userId, oldPwd, newPwd);
return ResourceResponse.getResourceJsonString(res.getObjectJsonString(), callback, res.getSuccess(), res.getCode());
}
else
{
return ResourceResponse.getResourceFailResponseString(callback, ErrorMessageEnum.USER_NOT_CONNECTED);
}
}
}
SessionManager.java
public static void loginUserToSession(HttpServletRequest req, short userId, String userName)
{
if(req == null)
{
return;
}
HttpSession session = req.getSession(true);
session.setAttribute(ATTRIBUTE_USER_NAME, userName);
session.setAttribute(ATTRIBUTE_USER_ID, userId);
session.setAttribute(ATTRIBUTE_USER_CONNECTED, true);
}
public static boolean isUserConnected(HttpServletRequest req)
{
if(req == null)
{
return false;
}
HttpSession session = req.getSession(false);
if(session != null)
{
boolean userConnected = (boolean) session.getAttribute(ATTRIBUTE_USER_CONNECTED);
if(userConnected)
{
return userConnected;
}
System.out.Println("session.getAttribute(ATTRIBUTE_USER_CONNECTED)== null");
}
return false;
}
Please change into Resource like this:
public String loginUser(#Context HttpServletRequest req #QueryParam("callback") String callback, #QueryParam("loginInfo") LoginInfo loginInfo) throws JsonProcessingException
{
if(SessionManager.isUserConnected(req))
{
return ResourceResponse.getResourceJsonString("null", callback, "true", ErrorMessageEnum.SUCCESS);
}else{
String userName = loginInfo.username;
String plainTextPassword = loginInfo.password;
UserEntity user = objectDao.logIn(userName, plainTextPassword);
if(user != null)
{
SessionManager.loginUserToSession(req, user.getUserId(), userName);
return ResourceResponse.getResourceJsonString(user.getUserStatus(), callback, "true", ErrorMessageEnum.SUCCESS);
}
}
}
Above was the flow error , whatever i got, Now you have to setattribute into session scope then use this:
HttpSession session = request.getSession();
session.setAttribute("UserName", "Usename_Value");
Or for request Scope use this:
request.setAttribute("attributeName",yourStringVAlue);
It turns out that for some reason google postman don't send the HttpServletRequest as it should be. so jersey translate it like new user and create an empty new HttpServletRequest. Conclusion do not test your server side with Google's postman
when i try to send the request from my client it work fine.

Apache cxf delete request error

I'm trying to use #DELETE request after a made some simple web application which I've tested using soapui. With this application I can add and get users/book to database. Now I'm trying to made a #DELETE request but I can't make it. Here is the code:
//UserServiceImpl
#PersistenceContext
private EntityManager em;
#Override
public void deleteUser(Long id) {
if (null == id || id.longValue() < 1) {
throw new IllegalArgumentException(" User id can not be null or less than zero. ");
}
User u = em.find(User.class, id);
em.remove(u);
}
//UserResource
#Autowired
private UserService userService;
#DELETE
#Path("/delete/{id}")
public Response deleteUser(#PathParam("id") String id) {
Response response;
try {
User user = userService.deleteUser(Long.valueOf(id));//here is the error
if (user != null) {
response = Response.status(HttpServletResponse.SC_OK).entity(user).build();
} else {
response = Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
} catch (IllegalArgumentException e) {
response = Response.status(HttpServletResponse.SC_NOT_FOUND).build();
}
return response;
}
I`ve fix my problem. The delete method which is in UserServiceImpl must not be void.... it must be public User deleteUser(Long id). The other delete method in Resource class ... just need to be of void type. There i do not use Response and i simply print the result like this:
System.out.print(Response.status(HttpServletResponse.SC_OK).entity(user).build());

Spring social siginIn() not firing on successful authentication

I've implemented Spring Social and have successfully been able to implement the ProviderSignInController to authenticate connections to Facebook.
As part of this I needed to implement the SignInAdapter interface. I understand this interface is used in the final steps of a successful authentication with a provider, specifically I'm overriding the signIn method to log the client into my application programmatically after successful authentication with the provider.
My problem is that when I implement the SignInAdapter it doesn't fire the signIn() method on successful login.
The code is almost straight out of the Spring showcase examples:
public class SimpleSignInAdapter implements SignInAdapter {
private static final Logger logger = LoggerFactory.getLogger(SimpleSignInAdapter.class);
private final RequestCache requestCache;
#Inject
public SimpleSignInAdapter(RequestCache requestCache) {
this.requestCache = requestCache;
logger.debug("Constructing " + SimpleSignInAdapter.class.getCanonicalName());
}
#Override
public String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
/* A social profile has been found. Now we need to log that user into the
* application programatically.
*
* No other credentials are necessary here because by the time this method
* is called the user will have signed into the provider and their connection
* with that provider has been used to prove the user's identity.
*/
logger.debug("A social profile has been found. Now we need to log that user into the app.");
SignInUtils.signin(localUserId);
return null;
}
private String extractOriginalUrl(NativeWebRequest request) {
HttpServletRequest nativeReq = request.getNativeRequest(HttpServletRequest.class);
HttpServletResponse nativeRes = request.getNativeResponse(HttpServletResponse.class);
SavedRequest saved = requestCache.getRequest(nativeReq, nativeRes);
if (saved == null) {
return null;
}
requestCache.removeRequest(nativeReq, nativeRes);
removeAutheticationAttributes(nativeReq.getSession(false));
return saved.getRedirectUrl();
}
private void removeAutheticationAttributes(HttpSession session) {
if (session == null) {
return;
}
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
}
The interesting this is that the SimpleSignInAdapter is constructed as I can debug through that step and see my debug output in the log so it seems the Bean is being instantiated just not firing the signIn method.
Here's my Spring configuration:
#Configuration
#ComponentScan(basePackages = "com.mycompany.webclient")
#PropertySource("classpath:app.properties")
#ImportResource("/WEB-INF/spring/appServlet/security-app-context.xml")
public class MainConfig {
#Bean
public PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
And my Spring Social config is:
#Configuration
#EnableSocial
public class SocialConfig implements SocialConfigurer {
private SocialUserDAO socialUserDao;
//
// SocialConfigurer implementation methods
//
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
cfConfig.addConnectionFactory(new FacebookConnectionFactory("XXXXXXXXX", "XXXXXXXXX"));
cfConfig.addConnectionFactory(new TwitterConnectionFactory("XXXXXXXXX", "XXXXXXXXX"));
}
#Override
public UserIdSource getUserIdSource() {
return new UserIdSource() {
#Override
public String getUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
}
return authentication.getName();
}
};
}
#Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
return new HibernateUsersConnectionRepository(socialUserDao, connectionFactoryLocator, Encryptors.noOpText());
}
//
// API Binding Beans
//
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook(ConnectionRepository repository) {
Connection<Facebook> connection = repository.findPrimaryConnection(Facebook.class);
return connection != null ? connection.getApi() : null;
}
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Twitter twitter(ConnectionRepository repository) {
Connection<Twitter> connection = repository.findPrimaryConnection(Twitter.class);
return connection != null ? connection.getApi() : null;
}
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public LinkedIn linkedin(ConnectionRepository repository) {
Connection<LinkedIn> connection = repository.findPrimaryConnection(LinkedIn.class);
return connection != null ? connection.getApi() : null;
}
//
// Web Controller and Filter Beans
//
#Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
ConnectController connectController = new ConnectController(connectionFactoryLocator, connectionRepository);
connectController.addInterceptor(new PostToWallAfterConnectInterceptor());
connectController.addInterceptor(new TweetAfterConnectInterceptor());
return connectController;
}
#Bean
public ProviderSignInController providerSignInController(ConnectionFactoryLocator connectionFactoryLocator, UsersConnectionRepository usersConnectionRepository) {
return new ProviderSignInController(connectionFactoryLocator, usersConnectionRepository, new SimpleSignInAdapter(new HttpSessionRequestCache()));
}
#Bean
public DisconnectController disconnectController(UsersConnectionRepository usersConnectionRepository, Environment env) {
return new DisconnectController(usersConnectionRepository, env.getProperty("facebook.clientSecret"));
}
#Bean
public ReconnectFilter apiExceptionHandler(UsersConnectionRepository usersConnectionRepository, UserIdSource userIdSource) {
return new ReconnectFilter(usersConnectionRepository, userIdSource);
}
}
Is there any way for me to confirm why the signIn() is not being fired or even if it is being registered.

Managed bean is sometimes null and sometimes not

I have a managed bean LoginBean:
#ManagedBean(name = "loginBean")
#SessionScoped
public class LoginBean implements Serializable {
private String email, password;
private BasicUser user;
/** Creates a new instance of LoginBean */
public LoginBean() {
}
public void setUser(BasicUser user) {
this.user = user;
}
public BasicUser getUser() {
return user;
}
...
}
And then a PhaseListener who gets the sessions loginBean.
public class FacebookSignInListener implements PhaseListener, UserService {
private LoginBean bean;
....
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
#Override
public void afterPhase(PhaseEvent event) {
HttpSession session = (HttpSession) event.getFacesContext().getExternalContext().getSession(true);
bean = (LoginBean) session.getAttribute("loginBean");
bean.setUser(facebookUser);
}
#Override
public void beforePhase(PhaseEvent event) {
FacesContext fc = FacesContext.getCurrentInstance();
request = (HttpServletRequest) fc.getExternalContext().getRequest();
boolean isLoginPage =
(fc.getViewRoot().getViewId().indexOf("welcome") > -1);
if (isLoginPage) {
try {
FBOauth fbo = new FBOauth(this);
fbo.doLogin(request);
} catch (IOException ex) {
Logger.getLogger(FacebookSignInListener.class.getName()).log(Level.SEVERE, "Could not exchange code for access_token. Page where not found.", ex);
}
}
}
#Override
public boolean authFacebookLogin(String accessToken, FacesContext fc) throws FacebookException {
if (accessToken != null) {
FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
User fbUser = facebookClient.fetchObject("me", User.class);
UserHelper uh = new UserHelper();
FacebookUser facebookUser = (FacebookUser) uh.getByFacebookId(fbUser.getId());
// Does the user already exist and is he already connected with facebook.
if (facebookUser != null) {
return true;
}
}
}
}
When I after deploy on the admin console press launch application, logs into my application via facebook there is no problem with the code below. I can logout and log in again and still no problem. If I then change browser and tries to login via facebook here I get a NullPointerException where I do
bean.setUser(facebookUser)
This also happens if I close the first browser, opens again and tries to login via facebook. Why is this happening?
I am using Glassfish v3.
If the session scoped bean is null then it simply means that it hasn't been created for the session yet. This can happen during the very first request of a fresh session. You've to create it yourself and put it in the session scope yourself. JSF will just reuse it in the remnant of the session.
Your way of grabbing the session scoped bean is a bit clumsy. You're getting the raw Servlet API from under the JSF's hoods. You could also just use ExternalContext#getSessionMap() to manage the session attributes.
Map<String, Object> sessionMap = externalContext.getSessionMap();
LoginBean loginBean = (LoginBean) sessionMap.get("loginBean");
if (loginBean == null) {
loginBean = new LoginBean();
sessionMap.put("loginBean", loginBean);
}
// ...
Note that you shouldn't declare the bean as an instance variable of the PhaseListener. There is namely a single PhaseListener instance throughout the application's lifetime, so all instance variables would be shared among all requests/sessions. In other words: it's not threadsafe.
Seems like you are trying to use the bean before it was created since your PhaseListener is firing in the first Phase. Have you tried to shift it to a later phase?
Edit:
You access the session with the crate flag set to true:
HttpSession session = (HttpSession) externalContext.getSession(true);
Thus, your newly created session wont include any session scoped beans.
The Framework will instantiate the session scoped Bean and put in the session object when an expression referencing the bean is evaluated, which is not the case here.

Categories