I learnt how to use container authentication with JDBC realm.
I searched a lot on internet but I couldn't find anything on JSF authorization except the following article.
JSF authorization
My goal is to avoid access to protected pages using direct links and to show/hide menu items and form components based on the authenticated user privileges.
The last part can be implemented using the rendered attribute of JSF tags but before creating my own dirty and high coupled solution I wonder if there are some specific best practices or libraries that can help. in fact the number of components to be conditionally rendered is quite high and I wouldn't like to write a specific function for each of them.
Perhaps I can create for each authenticated user a map with the names (id) of all the conditionally rendered components and a single function with a String parameter (the unique name/id of the component). Is that a good idea ? What alternatives do I have ?
I wouldn't like to add to the project other general purpose frameworks such as spring for using only a small part of them (the security one).
Thanks
Filippo
With the Expression Language version in Java EE 6 you should be able to use expressions like these:
<h:inputText rendered="#{facesContext.externalContext.isUserInRole('foo')}" />
With older versions, you can create a managed bean of this form:
public class RoleMap implements Map<String, Boolean> {
public Boolean get(Object key) {
ExternalContext extCtxt = FacesContext.getCurrentInstance()
.getExternalContext();
return extCtxt.isUserInRole(key.toString());
}
//TODO: other methods; mostly throwing UnsupportedOperationException
The test can then be expression in the form:
<h:inputText rendered="#{roleMap['foo']}" />
Third party frameworks offer other options, such as the Apache Tomahawk library's visibleOnUserRole component attributes.
Take a look at Apache Shiro, a dedicated security framework (and supposedly erasier to use than Spring Security).
Related
We have an application (Mojarra 2.3) where a user can change a global filter of the data it sees. When that happens, I want to keep the session, but invalidate the active views (which are server side).
I found this question which enables you to count the number of views: How do I count the number of views in a user's JSF session (JSF 2.2)?
Based on that I figured I could remove the attribute in which the views are stored. I came up with this method:
public static void invalidateViews() {
final HttpSession session = Faces.getSession();
List.of("com.sun.faces.application.view.activeViewContexts",
"com.sun.faces.application.view.activeViewMaps",
"com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap",
"org.jboss.weld.context.ConversationContext.conversations")
.forEach(session::removeAttribute);
Faces.redirect(Faces.getRequest().getRequestURL().toString());
}
The com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap was mentioned in the linked question's answer. I kind of guessed that it would not hurt to remove the other attributes. The answer also mentions that it is Mojarra only.
It seems to work so far, but I would like to ask this: should one clear server side views like this? And, if so, how can I support MyFaces as well?
It seems to work so far, but I would like to ask this: should one clear server side views like this?
Given that there is no standard API call for this, this is about the best you can do, yes. I have during the JSF 2.3 work requested for a more specific variant of this functionality to exist in the standard API because I needed to be able to destroy view scoped beans associated with a specific JSF view state (for the OmniFaces view scope unload functionality, see Hacks#removeViewState()). But this has unfortunately not yet been fleshed out because of difficulties with Portlets.
And, if so, how can I support MyFaces as well?
As seen in the OmniFaces Hacks helper class, the session attribute key for MyFaces 2.x is org.apache.myfaces.application.viewstate.ServerSideStateCacheImpl.SERIALIZED_VIEW and 4.x org.apache.myfaces.application.viewstate.StateCacheServerSide.SERIALIZED_VIEW.
By the way,
Faces.redirect(Faces.getRequest().getRequestURL().toString());
this is shorter:
Faces.refreshWithQueryString();
I'm working on a JSF webapp which purpose is to wrap a command-line program.
One of its main functionality is the ability to share a session between users (eg. for courses purpose), so that when an input is sent to an instance of the application, the output sent to every subscriber for this session.
As a result of this design, the webapp is mainly composed of a view-scoped bean which will request a controller of the command-line application.
It has also been chosen to identify a session with the URL fragment (eg. mydomain/myapp/#SESSIONID), so that anyone using the URL with the same fragment will share inputs and outputs, using its own instance of the view-scoped bean but sharing the same controller
In order to push results to all subscribers, I'm using Primefaces Push. Results are primarily text that has to be appened to the webapp's terminal, but some commands lead to the programmatic creation of a JSF component.
In order to handle this, I just render these components to a string that I send to all subscribers.
Then, I realized that in order to handle ajax requests from components (and from every subscriber), the associated UIComponent needs to be added to the UIViewRoot in the context of (don't know how to express this) each view-scope bean.
As a matter of fact, I first tried to bind a "common container" (a UIForm) to a property of the view scoped bean, in which I would put the programmatically created components, but I obviously had to face the chicken/egg issue #BalusC talks about in his blog, because the component was added again on each ajax request. Setting javax.faces.PARTIAL_STATE_SAVING to false didn't help either (I'm using MyFaces 2.2.5)
So, as somewhat of a workaround, when the controller needs to create a new component, it basically adds the id of the component to the data pushed (in a HashMap converted to Json), and all subscribers will trigger (back) a remoteCommand to its own instance of the view-scoped bean, in order to update the "common container" from its own UIViewRoot.
This does work, but I don't like this way of doing it!
So:
would it be possible to handle this kind of sharing between view-scope beans (with the same name) which are stored in different HTTP sessions? I'm refering to this answer from #BalusC... maybe playing with javax.faces.ViewState - would it even be possible?
Is there a "magical" scope for my currently-view-scoped bean I could use?
Shall I rather use a completely different design?
Thanks!
If you want share data between all your application users you can use application scope.
If you still want to use view scope, you can connect your view scope with another application scope like this:
ApplicationView appView = BeanUtil.findBean("applicationView", FacesContext.getCurrentInstance());
import javax.faces.context.FacesContext;
public class BeanUtil {
#SuppressWarnings("unchecked")
public static <T> T findBean(String beanName, FacesContext context) {
return (T) context.getApplication().evaluateExpressionGet(context,
"#{" + beanName + "}", Object.class);
}
}
In the past I used a lot of getter and setter methods to move as much boolean logic as possible from facelet files to JSF backing beans.
This way, the interface of a view was given by the getter and setter methods of its backing bean as well as by the action methods of the backing bean.
An advantage of this approach is that the facelet files are rather logic-free and ,therefore, all logic is within the backing beans and can be unit tested.
But with EL 2.2 another programming style became possible. In EL 2.2 you can invoke methods with expressions like
#{bean.collection.size()},
#{bean.collection.add(elem)},
#{bean.property.substring(0, bean.property.indexOf(something))}.
Is the usage of rather complex expressions like parameterized method invocations good style now or do you rather advise against using such expressions?
Is there a rule of thumb when to use the new method invocation expressions and when not?
The major guideline is the following: reduce as much 'model' logic from the view as possible and leave only the 'view' logic. EL 2.2 made possible some model simplification and reduced the need for creation of artificial properies of JSF beans. Invocation of methods with parameters also enables to pass the necessary information from the view to the controller which would be tedious without that opportunity.
You can call arbitrary methods to access the model from the view that the view part relies on, but you should never call methods that modifies the model from the view.
Let me elaborate on that.
Some legal examples:
evaluate non-accessor methods when building view:
render UI components based on some conditions like rendered="#{request.isUserInRole('administrator')}";
make collection modifications where necessary like <ui:repeat value="#{bean.set.toArray()}" ... >
conditionally evaluate UI component / HTML element attributes like class="#{bean.name.contains('special') ? 'special' : ''}";
output non-accessor data like there are #{bean.list.size()} elements.
pass information to the controller in action methods or listeners:
execute action methods with currently iterated variables like var="data" and action="#{bean.action(data)}" with public String action(Data data);
pass additional data, like current iteration index, in listeners like varStatus="status" and actionListener="#{bean.action(status.index)}" with public String action(int index).
Some to-be-avoided examples:
use EL operators when possible:
use #{not empty bean.list} instead of #{bean.list.size() gt 0}.
use method call with parameters instead of extending the model:
use #{bean.name.contains('special')} instead of #{bean.special} with public boolean isSpecial() {return name.contains("special");}.
prefer leaving view logic in view for plain rendering of the right things and create model logic in case it applies purely to the model:
in case you need to perform some calculations to change the appearance of an object, do that in view directly without changing the model, in case some property is inherent to the model itself, introduce it directly in the model and refer to it from the view.
Some illegal examples:
modify the model from the view:
do not use EL 2.2 possibility of calling methods with parameters to break the MVC paradigm, i.e. do not call #{bean.list.add(element)} from the view side.
Of course, all things said apply to the cases that your goals don't contain targeting at the older servers without EL 2.2 support.
As a bigger picture, I'd recommend to also see BalusC's explanation of what MVC architecture represents within the context of JSF.
Personally, i prefer using "complex" EL expressions when really needed, and take any bit logic/traitement to the correspondant managed-beans.
For example: the first example you put is the only one that i may sometimes use directly, the two others however should be for me put in action methods with void/String returning type according to the need.
Use El 2.2 to reduce our JSF code, e.g. setPropertyActionListener is made redundant, see
JSF Core Tag :setPropertyActionListener vs attribute vs param
Each example I've seen for Faces Flow involves exclusive views that are only used within the particular flow. What I would like to do is create a flow that consists almost entirely of views that will be used in more than one flow, and/or potentially outside of a flow. Is this reusability of views possible, or were Faces Flows not meant to be used this way?
Faces Flow example from JavaEE 7 doc
Faces Flow is basically composed (or can be) by JSF views, being themselves reusable. If you refer to this post:
What's new in JSF 2.2 for flows ?
The flow of application is no longer restricted to flow between pages but instead defined as flow between "nodes". There are five different types of nodes:
View: Any JSF page in the application
Method Call: Invoke application logic from flow graph via an EL
Switch: Navigation decisions in the flow graph based on boolean EL
Flow Call: Call another flow with parameters and receive return values
Flow Return: Return to the calling flow
The first point itself answers your question!
EDIT FROM OP (#jdessey)
I've confirmed the accepted answer in testing, and wanted to share a few caveats in implementation.
Programmatic flow definition (i.e. #FlowDefinition annotation) is only processed if the class that contains the annotated method is itself a normal scoped CDI bean such as `#ApplicationScoped`. (Might be a bug - I'm using JSF 2.2.4 and Weld 2.0.4)
When defining the view node using FlowBuilder.viewNode(String viewNodeId, String vdlDocumentId), the document id must be the absolute path to the .xhtml file. This is in the javadoc but not intuitive IMO because since 2.0 we are used to implicit navigation.
Code:
#ApplicationScoped
public class MyFlow implements Serializable {
#Produces #FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
flowBuilder.id("", "myFlow");
flowBuilder.viewNode("anyView", "/absolutePathToView.xhtml").markAsStartNode();
return flowBuilder.getFlow();
}
}
Now to navigate to this flow, just use "myFlow" as an implicit navigation case such as:
<p:menuitem value="Begin Flow" action="myFlow" />
Let's say I've got a register page & a register confirm page. I enter user
details into the register page, navigate to the register confirm page where
I can return back to the register page if there are any mistakes.
I'm going to use view parameters to make the registration data available
from the register page to the confirm page, and vice versa.
Supposing there are 20 items of data to be moving from page to page, that's
a lot of view parameters and a lot of setPropertyActionListeners, especially
as all the data is going to end up nicely packaged in a User object.
So what I want to do is input the data on the register page into the
properties of a User record and send a reference to it to the register
confirm page. What gave me an idea was seeing the BalusC WeakHashMap
converter. This is a JSF converter which has a static weak hash map and
generates a uuid as the value for a map entry and the object reference as
the key. So by specifying this as a converter for f:viewParam you send
the uuid in the query string.
This works fine. The issue I have is that on the register page I have to
get an instance of a User class with new. Then I can do:
<h:inputText value="#{bean.user.firstname}"/>
(etc...), and pass the user instance as a view parameter. It works fine from
the register to the confirm page. The issue is that when I perform the
reverse, sending the user reference back to the register page from the
confirm page I absolutely cannot prevent the register page backing bean
from re-instantiating the user object, after the setter has been called
as a result of the view parameter.
So the converter does it's job and retrieves the User object from the
hash map, calls setUser() in the backing bean, and then I see the
constructor for the User class firing.
I've tried calling new User() from the bean constructor, in #PostConstruct,
in a preRenderView (also checking if an ajax request), but nothing I try
prevents the work of the view parameter from getting wiped out if new is
involved. I'm sure there's a simple solution but I just can't see it right
now.
I'd be grateful for any suggestions for how to solve this problem.
The issue I have is that on the register page I have to get an instance of a User class with new.
So what code is initially creating this new User instance then? If you do this in the preRenderView handler, then you can simply check for null, can't you?
If the view parameter and converter haven't done their job, user would still be null and you create a new instance. The bean constructor and #PostConstruct won't do you any good here, since they both run before the view parameter does its thing, but the preRenderView event is guaranteed to run after it.
#ManagedBean
public class Bean {
private User user;
public void onPreRenderView() {
if (user == null) {
user = new User();
}
}
}
(Something to additionally consider is that the conversation scope already does exactly what you're trying to do here. This is part of CDI not JSF, but if you're running in a Java EE 6 Web Profile compliant AS (JBoss AS 6 or 7, Glassfish V3, Resin 4, ...) you already have it. Otherwise it's just an extra jar.)
After several attempts over more than a year to find a solid long term solution
to this problem, at last! I've found one. The solution comes in the form of the
Apache Myfaces CDI extensions project, aka Myfaces CODI.
This provides additional scopes such as the #ViewAccessScoped which ensures that
if a bean is referenced by a page then it is available for that page. Also
provided is support for conversation groups. In the scenario where I want to
pass an object reference from a register page to a register confirm page, the
confirm page can just access the registerView bean directly on the next request.
Alternatively you can #Inject one bean into another and access it on the next
request, or use f:setPropertyActionListener from the source page.
Myfaces CODI works fine with Mojarra and also with ajaxified component libraries
such as primefaces. The concept is similar to what is provided by Jboss Seam,
though I've found the additional scope support to be better thought out and I've
tested this on glassfish 3.1.1 with no problems.
If you're using #ManagedBean and scope annotations from the javax.faces.bean
package in your code, codi intercepts these annotations and uses it's own
CDI based versions, so you can convert to CDI simply by adding codi as a
dependency to your project and not changing any code.
For me this is like moving from black and white TV to colour TV, I wish I'd
found this stuff sooner.
CODI documentation