Win a copy of Murach's Python Programming this week in the Jython/Python forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Passing a value to a bean on page load  RSS feed

 
J Miller
Ranch Hand
Posts: 80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm setting up an application where, when the page loads, a bean method will be called to see if the authenticated user has access to the page. The way we've done it in past applications is to call a method upon page load that checks if that user has permission. Each page is given a page code, and we would call a method that would say "does this user have access to this page code"? The problem with the previous application, is that every time you created a new page, you had to go into the bean and create a new method for that particular page. I'd like to change it so that the xhtml passes the page code to the bean, and I can just use a single method.

I've had some success using the preRenderView tag like this:

xhtml


TestBean.java


This works, and I can use this if needed. I'd like to abstract it a bit though, and make it a component.

Component


When I do this, the bean prints

testPagePermission(#{cc.attrs.pageCode})


If we need to, we can al ljust put the preRenderView tag on every page, but I'd like to be able to obscure it using either a component or JSF templating. Any ideas on how to accomplish this?
 
Tim Holloway
Bartender
Posts: 18531
61
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
JSF is a little funny that way, but before I get into that, I'll make my standard disclaimer that the technical term for Do-It-Yourself login/security systems is "hacked".

If you like, I can point you to a long list of reasons why it's almost always better to use the security that was designed by full-time security professionals and built into the J2EE spec itself than to use something proudly designed by your in-house resident genius.

Case in point: The J2EE security spec basically gives you what you are describing for free with no user coding required, no need to train new programmers in how to work with the (probably undocumented) in-house security interface, no worries about bugs in the security code. Instead of attaching security to "page load", you define a rule in the WEB-INF/web.xml file that matches the corresponding URL. That will cause the application server to validate access against the selected security manager (Realm), and unauthorized requests will be bounced BEFORE they can reach - and possibly exploit - application code.

JSF is a fairly pure implementation of the Model/View/Controller paradigm and as such "page load" is actually shorthand for "navigate to a new View". But from a security standpoint, first-time access control is doubtful. If you want to prevent unauthorized users from seeing a view, it's better to use a system where any attempt to access the View is prohibited to unauthorized users. Just in case someone manages to find and exploit a way around the "page load" logic. Here again, the J2EE standard container security already gives that assurance. At the server level.

JSF does have one quirk when you use container-managed security, though. Since the primary guard mechanism is based on the URL and not on the end components - AND since JSF URLs are normally prone to lag behind the actual resource being requested, navigation rules that lead into sensitive areas need to be qualified with the "redirect" element. That will (at the cost of some small overhead) ensure that the URL and target resources are in sync so that the URL filter in the security system will operate properly.
 
J Miller
Ranch Hand
Posts: 80
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is it possible to use a mix? The company I work for uses LDAP as a standard. The application that I'm writing will give certain users the ability to create new user roles, assign different levels of page privileges to different pages, and assign those roles to users. So it needs to be something that can be done programatically, rather than each page having the privileges hard coded. It would be nice, though, if it were possible to put something in the web.xml that says "don't let the user in unless they have the correct LDAP token." The idea being that you have to have the LDAP token to gain access to the system but, once you're in, the level of access is determined by your role.

If it helps, we're using JSF 2, PrimeFaces 5.1, and Websphere 8.5.
 
Tim Holloway
Bartender
Posts: 18531
61
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The standard security system is fairly coarse-grained. Using it, you can define users and assign one or more role to each user (actually, zero or more, but zero roles means that only unsecured parts of the app are accessible).

So, for example, one webapp I did has an admin role, a manager role, an employee role and an auditor role. Auditors, unlike employees can only view data, not enter/change it.

And that's all that app needed. If I wanted a fine-grained matrix I could overload that with a system containing more subtlety. That way logins would be automatically enforced (a common exploit in DIY systems is to find a way around the login test, and the server's authenticator doesn't permit that). And you can likewise block out entire sections of an app (such as the admin functions) at the role level.

For a finer approach, I'd generally construct a session-scope object to hold the fine-grained security context. That could then be used as the authorizer for the more subtle aspects and could, for example, serve as a cache for frequently-used security rules so that an LDAP query wouldn't have to be done on every incoming request. If I was really into security, I'd probably even define some custom annotations to attach to critical action methods (such as "save" and "delete"). That would allow constructs like this:



The injected logic for the "AllowOnly" annotation would then consult with your security manager, and could access both J2EE and your own custom security services transparently. And bounce unauthorized changes (throw an exception) before the user logic was invoked.

Likewise you can use features such as AOP to do similar things.

When implementing a system like this, I don't recommend tapping into the JSF lifecycle, since that only protects the JSF parts of the webapp. Instead, I recommend something more global such as a ServletFilter. That way you also protect JSPs and non-JSF servlets.

Note that when using the built-in security system, the userID of the current user can be found in the getRemoteUser() method of the HttpServletRequest. In JSF, I try to keep framework-dependent code and constructs out of the application logic, so I have a special JSFUtils class I create that features such functions as "JSFUtils.getUserId()" and "JSFUtils.isCallerInRole(role_name)". That also makes unit-testing easier, since I can supply a mock JSFUtils and not actually have to have a webapp server running in order to do the tests.

If a user is not logged in, the remote userId is null. Otherwise you can use the userId as a key to look up user-specific data (including security authorizations) from whatever data sources (LDAP, database, whatever) that you like.

Note that there is no "login" event using container security. Container security supports Single Signon, so the user could have logged in via some other means long before they started using your app. You can tell when a user is logged in, however, by looking at the remote userID. If a user attempts to access a secured URL, login happens automatically.

The concept of Realms means that the web application neither knows nor cares whether you are using LDAP, databases, the tomcat-users.xml file, web services or some sort of mix-and-match deal. It's all transparent to the app. That's convenient for testing, especially if you have to run hurdles to get LDAP changes applied for testing. You can test using tomcat-users.xml (MemoryRealm) and run in production using LDAPRealm. Of course, if you've created a second-stage security manager and it's reaching out for additional security information, that part would be more closely tied to specifics - unless you abstract it into a generalized interface.

Finally, if you're planning on making the application alter security rules, think twice. Managing security is usually not a core business function in most webapps. In fact, in large corporations, it's common to have an entirely separate corporate department whose sole job is to manage security and/or delegate it to selected authorized personnel. So I usually prefer to handle security management in a separate app. That way there's minimal danger of "leakage" where a non-security person can alter security. And you can have tighter restraints on the security app as a whole.

  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!