retrieve FacesContext sessionMap from an other context - jsf-2

I have a method to remove a session managed bean
public void invalidMyBean()
{
final Map<String, Object> sessionMap = FaceContext.getCurrentInstance().getExternalContext().getSessionMap();
sessionMap.remove("mySessionBean");
}
invalidMyBean() is also called from a Web Service.
In this case FaceContext.getCurrentInstance() is null, and I can't remove my bean.
I tried to store sessionMap as a field in my class, but removing from this object does'nt work.
Is there a way to retrieve sessionMap outside from a faceContext ?
thx

The ExternalContext#getSessionMap() is just an abstraction of HttpSession#get/set/removeAttribute(). So wherever you are in the servletcontainer (filter, servlet, webservice, whatever), once you've got a hand of the concrete HttpSession instance, then you should be able to use session.removeAttribute("mySessionBean") on it.
Note that this obviously only works when the webservice is been requested using the same HTTP session as the JSF application (the way you put this question — you seem to not understand at all how HTTP sessions work — suggests that this is not the case).

I answer to myself giving the working code for an applet in a JSF page sharing the same HttpSession. The applet talks to a web service on the server using JAX-WS.
in JSF page :
<applet ..>
<param name="commonSessionId" value="#{session.id}" />
Distance Sensor [Your browser doesn’t seem to support Java applets.]
</applet>
in applet init() :
#Override
public void init()
{
...
commonSessionId = getParameter("commonSessionId");
port = service.getWsAppletPort();
final Map<String, Object> map = new HashMap<String, Object>();
map.put("Cookie", Collections.singletonList("JSESSIONID=" + commonSessionId));
final Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, map);
requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
}
thanks again to BalusC for his great help !!

Related

Is there a way to change http request method in netflix zuul routing filter?

I'm trying to trasform http GET method call from legacy api server built with MVC1 pattern to new restful api server without any change of front-end source code using netflix zuul and eureka.
I added zuul pre filter transforming legacy url to restful convention url working after PreDecorationFilter and it works fine.
But now I'm facing problem converting the GET method to proper method like POST, PUT, DELETE by distinguising url so that the requests are properly mapped in spring controller via #GetMapping/#PostMapping/#PutMapping/#DeleteMapping.
I looked into SimpleRoutingFilter that handles HttpClient but
Because of environmental constraint, I have to use eureka service id to route to the new api server and that means I should use RibbonRoutingFilter which is quite complicated to find out a right place to this operation in.
So, is this possible to change http method or make new http request before RibbonRoutingFilter?
If possible can you please suggest where is the right place to do that or some reference?
Many thanks!
======================================================================
Milenko Jevremovic,
Would you please tell me more detail about using Feign?
I defiend #FeignClient like below
#PostMapping(value = "{url"}, consumes = "application/json")
ResponseEntity<?> postMethod(#PathVariable("url") String url);
and to get query parameters to request body for POST In zuul pre filter,
after transform logic from GET request url to POST new restful url ...
byte[] bytes = objectMapper.writeValueAsBytes(ctx.get("requestQueryParams"));
ctx.setRequests(new HttpServletRequestWrapper(request) {
#Override ..getMethod
#Override ..getContentLength
#Override ..getConentLengthLong
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
}
ResponseEntity<?> response feignClient.post(transformedNewApiUri);
and set RequestContext code that you suggested ....
and controller of new api server is like,
#PostMapping
ResponseEntity<model> post(#RequestBody req..)
It comes to controller fine but when I see the http request in post method of controller,
There is no request body for parameters.
(HttpServleterRequest getInputStream shows empty)
The request data set in zuul pre filter by HttpServletRequestWrapper is
not used in Feign maybe...?
Would you please get me more idea setting request body when changing GET query
to POST constructor for using Feign?
It is not possible to change method of HttpServletRequest, but it's possible to replace request in RequestContext. HttpServletRequestWrapper appears to be very helpful:
static class PostHttpServletRequest extends HttpServletRequestWrapper {
public PostHttpServletRequest(HttpServletRequest request) {
super(request);
}
#Override
public String getMethod() {
return "POST";
}
}
So method run can be rewritten as following:
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletRequest requestWrapper = new PostHttpServletRequest(request);
ctx.setRequest(requestWrapper);
return null;
}
After doing some research did not find any built in solution.
But what comes in my mind you can use Feign client in your Pre filter, get the response, set the response and return it immediately to client from your Pre filter.
You can set Feign client url or your service id, like it is explained in the docs, it uses ribbon as well .
Change response in your run method like:
...
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setResponseStatusCode(your_code);
ctx.setResponseBody(new_body);
ctx.setSendZuulResponse(false);
return null

Vaadin Authentication and Auhorization

I'm new to Vaadin.
Before this I made a JSF Web Application.
I had a ManagedBean performing the login of the user. I used a security-realm to delegate the actual verification of the credentials.
How do I do this in Vaadin? Is there a best practice?
I'm at a point where I would just put something together, but there has to be some kind of standard-procedure, shouldn't it!?
I found some tutorials on this, but mostly using Spring (I want to use EJB).
Also, every tutorial seemed unneccessary complicated.
There has to be some simple+conclusive tutorial for something so common.
Here is the only Vaadin official article about how to secure a Vaadin aplication using JAAS that I could find. I mean native or official Vaadin Securization. You will find more if you google a little bit with Spring security, Shiro, but pure ESB uses JAAS.
I agree that this article is not enough to learn how to set up an application. I share here my experience:
1. Vaadin CDI extension:
<!-- Vaadin Official DI support. -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-cdi</artifactId>
<version>1.0.0.alpha2</version>
</dependency>
2. Understanding about JAAS
I suggest you to have a look how JAAS works in a non-vaadin application, by reading overview articles, because JAAS depends on Server application provider (TomEE,Jboss, Wildfly, Glasfish) all have different configuration settings.
Here you will find a proof of concept using Tomee.
3. Developing your own Login Module.
If you have decided to create a custom login module for example:
public class MyLoginModule implements LoginModule {
private CallbackHandler handler;
private Subject subject;
private UserPrincipal userPrincipal;
private RolePrincipal rolePrincipal;
private String login;
private List<String> userGroups;
#Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
handler = callbackHandler;
this.subject = subject;
}
#Override
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("login");
callbacks[1] = new PasswordCallback("password", true);
try {
handler.handle(callbacks);
String name = ((NameCallback) callbacks[0]).getName();
String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
// Here we validate the credentials against some
// authentication/authorization provider.
// It can be a Database, an external LDAP, a Web Service, etc.
// For this tutorial we are just checking if user is "user123" and
// password is "pass123"
if (name != null && name.equals("admin") && password != null && password.equals("admin")) {
login = name;
userGroups = new ArrayList<String>();
userGroups.add("admin");
return true;
}
// If credentials are NOT OK we throw a LoginException
throw new LoginException("Authentication failed");
} catch (IOException e) {
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
#Override
public boolean commit() throws LoginException {
userPrincipal = new UserPrincipal(login);
subject.getPrincipals().add(userPrincipal);
if (userGroups != null && userGroups.size() > 0) {
for (String groupName : userGroups) {
rolePrincipal = new RolePrincipal(groupName);
subject.getPrincipals().add(rolePrincipal);
}
}
return true;
}
#Override
public boolean abort() throws LoginException {
return false;
}
#Override
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
subject.getPrincipals().remove(rolePrincipal);
return true;
}
}
Reference it in the META-INF/context.xml of your application. This settings are for TomEE, but for glashfish or other must be similar.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Realm className="org.apache.catalina.realm.JAASRealm" appName="myrealm" userClassNames="net.sf.jaas.auth.UserPrincipal"
roleClassNames="net.sf.jaas.auth.RolePrincipal" />
</Context>
Be aware that userClassNames and roleClassNames are just simple Java Pojo but must implement java.security.Principal;
3. Enabling JAAS into your Vaadin Login View
Define your favourite login form, using Vaadin TextField and Password, and define in your doLoginEvent() a references to JAAS.
Whenever JaasAccessControl.login is called, a new instance of your LoginModule will be created.
import com.vaadin.cdi.access.JaasAccessControl;
try {
JaasAccessControl.login(loginEvent.getUsername(), loginEvent.getPassword());
logger.info("User {} authenticated", getPrincipalName());
navigator.navigateTo(Main.NAME);
} catch (Exception e) {
Notification.show("Error logging in", Type.ERROR_MESSAGE);
logger.error(e.getMessage(), e);
}
4. Using information of your logged user.
Whenever a user passes the JAAS login filter. It will be available in his request context a class that identifies him. This class is called Principal (the one you have previously set in the LoginModule class).
public boolean isUserInRole(String role) {
return JaasAccessControl.getCurrentRequest().isUserInRole(role);
}
public String getPrincipalName() {
Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
if (principal != null) {
return principal.getName();
}
return null;
}
public boolean isUserSignedIn() {
Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
return principal != null;
}
5. Alternatives to LoginModule
It's not mandatory to create your custom login Module, normally the Java EE providers as Tomee supply few implementation. Authentication based on properties file, in some database tables.
Have a look on Tomee documentation JAAS to see some examples:
6. Enable JAAS in TomEE
You need to create a jaas.config file which references you LoginModule, for example:
filename: jaas.config
myrealm{
net.sf.jaas.MyLoginModule required;
};
Then start the application server with this parameter:
-Djava.security.auth.login.config=E:/apache-tomee-jaxrs-1.6.0.2/conf/jaas.config
If you want to have a look a proof of concept of this. Checkout this example, which uses Tomee, Vaadin 7, JAAS,
I was running into the same problem a couple of months ago. I wasn't then able to figure out how it really works, so I went over the spring adddon and now I'm using a Vaadin login form and spring security
A full example that uses JAAS, Vaadin 8, Vaadin CDI add-on and the built-in LoginForm is available here, steps are as follows:
Enable the Vaadin CDI add-on in pom.xml
Enable CDI in Vaadin UI with #CDIUI annotation and configure the Navigator
Enable authorization in a CDI view by adding the #RolesAllowed annotation (or any other javax.annotation.security annotation)
Implement a login view that derives from the built-in LoginForm and uses JaasAccessControl to authenticate the user.
It is actually a rather nice, fluent experience once you figure out how the pieces fit together.
There's a longer article in Vaadin wiki that explains how to use database-backed authentication with JAAS.

Get the URL of current XHTML page which has user data filled in the form into the JSF Managed bean

I am working with creating PDF from XHTML with JSF 2.0 and iText. The page is simple registration form. When User enters all the data in the page and click on submit I have to get the whole HTML page source with user entered values into the bean. I used Jsoup to get the HTML but I got only HTML source not the values entered by the user.How can I do this?
My current code is
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpSession session = (HttpSession) externalContext.getSession(true);
String url = "http://localhost:8080/Pro/faces/part1.xhtml;JSESSIONID=" + session.getId();
try {
Document doc = Jsoup.connect(url).get();
Your Jsoup approach would only work if the managed bean holding the model data associated with the view is been stored in the session scope. Jsoup is namely firing a fresh new HTTP GET request, which thus means that it would in case of a request or view scoped bean get a brand new and entirely distinct instance, with all properties set to default.
If you want to keep your bean in the request or view scope (very reasonable), then you'd need to temporarily put the model data in the session before the Jsoup call and remove it after the Jsoup call.
Your another mistake is that you uppercased the JSESSIONID URL path fragment. It's case sensitive and it should in fact be all lowercase: jsessionid.
So, all with all, this should do if you want to keep your bean request or view scoped:
#ManagedBean
#ViewScoped
public class Bean {
#ManagedProperty("#{beanModel}") // Must match (unique!) session attribute name.
private Model model;
public void submit() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
HttpSession session = (HttpSession) externalContext.getSession(true);
String url = request.getRequestURL().append(";jsessionid=").append(session.getId()).toString();
session.setAttribute("beanModel", model);
Document doc = Jsoup.connect(url).get();
session.removeAttribute("beanModel");
// ...
}
}

#ManagedProperty object for authentication data is null

I have the following managed bean which stores the login data after container authentication:
#ManagedBean(name = "authenticatedUserController")
#SessionScoped
public class AuthenticatedUserController implements Serializable {
#EJB
private jpa.UtentiportaleFacade ejbFacade;
public Utentiportale getAuthenticatedUser() {
if (AuthenticatedUser == null) {
Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
if (principal != null) {
AuthenticatedUser = ejbFacade.findByLogin(principal.getName()).get(0);
}
}
return AuthenticatedUser;
}
getAuthenticatedUser is called in every page because I put the user name in a facelets template on the top right side.
In PermessimerceController, another managedbean, I need to access login data so it is easy and fast to inject the above session scoped controller:
#ManagedProperty(value = "#{authenticatedUserController}")
private AuthenticatedUserController authenticatedUserController;
I experienced the following problem: trying to access the page which is linked to PermessimerceController without being authenticated I'm redirected to the login page (and this is OK) but after that I get a null pointer exception because authenticatedUserController is null when it is injected inside PermessimerceController.
The page in question uses both PermessimerceController and AuthenticatedUserController so I should guess that for some reason PermessimerceController is created before AuthenticatedUserController. Can you suggest a simple way to solve this problem ?
Alternatively how can I store the login data in an easy to access place ?
Thanks
Filippo
I try to edit this post in the hope to clarify better the problem I have and find useful answers.
Using facelets templating I show the user login name throught a property of AuthenticatedUserController. The rest of the content is linked to PermessimerceController which needs some informations about the user for filtering data. The #ManagedBean annotation is an easy way to accomplish this. Unfortunately if the user access that page without being authenticated the injected AuthenticatedUserController is null. So it seems PermessimerceController is created before AuthenticatedUserController and I wonder why. Is there a trick I can use for being sure AuthenticatedUserController is create before ?
You were apparently accessing it in the bean's constructor:
#ManagedProperty("#{authenticatedUserController}")
private AuthenticatedUserController authenticatedUserController;
public PermessimerceController() {
authenticatedUserController.getAuthenticatedUser(); // Fail!
}
This will indeed not work that way. The bean is constructed before the dependencies are injected (think about it; how else would the dependency injection manager inject it?)
The earliest access point is a #PostConstruct method:
#ManagedProperty("#{authenticatedUserController}")
private AuthenticatedUserController authenticatedUserController;
#PostConstruct
public void init() {
authenticatedUserController.getAuthenticatedUser(); // Success!
}

Managed bean property not maintained in the next page by #ManagedProperty

I am new for JSF. In my project am using #ManagedBean, #RequestScoped. Am using 4 pages in my project. My problem was bean values not maintain in the second, third and fourth pages. Am using getter and setter properly. If i not use #ManagedProperty the bean value maintained properly. But i need to use the
#ManagedProperty. Could you please advise me how to solve this issue. I have copied some sample code for reference.
#ManagedBean
#RequestScoped
public class ArticlePrepToolManagedBean implements Runnable, Serializable {
#ManagedProperty (value="#{param.jidName}")
private String jidName;
#ManagedProperty (value="#{param.aidName}")
private String aidName;
private List<com.elsevier.ArticlePrepTool.db.ItemZipContains> usabilityDetailList = null;
public String getAidName() {
return aidName;
}
public void setAidName(String aidName) {
this.aidName = aidName;
}
public String getJidName() {
return jidName;
}
public void setJidName(String jidName) {
this.jidName = jidName;
}
public List<ItemZipContains> getUsabilityDetailList() {
return usabilityDetailList;
}
public void setUsabilityDetailList(List<ItemZipContains> usabilityDetailList) {
ArticlePrepToolManagedBean.usabilityDetailList = usabilityDetailList;
}
}
My project url is (http://localhost:8080/articlepreptool/) but input for my project is jidName=AEA aidName=10663. that input given by some other webpage that is if user trigger using the following href "PrepTool". Depends on the input i fetched some data in my project DB (using JPA) and list out the data in the first page. But if i goes to next page all previous data stored in that list which i got from DB was cleared that is all list values and variables which set in the bean becomes null. So could you please advise me how to solve this issue.That problem occured only if i used the #ManagedProperty. I used #ManagedProperty to fetch the input values comes through url, because the input values of my project comes through other web page.
A #ManagedProperty("#{param.foo}") basically sets the HTTP request parameter with name "foo" as a bean property directly after bean's construction. If you're retrieving null values for them, then it simply means that those parameters are not present in the HTTP request.
Assuming that you're navigating by a plain link, then you need to fix your links to include the request parameters:
<h:link value="Go to page2" outcome="page2">
<f:param name="jidName" value="#{bean.jidName}" />
<f:param name="aidName" value="#{bean.aidName}" />
</h:link>
This will result in something like:
<a href="page2.xhtml?jidName=foo&aidname=bar">
This way those parameters can be set as bean properties.
Alternatively, instead of #ManagedProperty you could also use <f:viewParam> on all pages and add includeViewParams=true to the outcome. See also ViewParam vs #ManagedProperty(value = "#{param.id}")
If you're navigating by a form submit, then there's really no reason to use them. Or you must be abusing forms instead of links for plain vanilla page-to-page navigation.

Resources