Add Security in the View Layer"

From Documentation
 
(24 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
{{ZKSpringEssentialsPageHeader}}
 
{{ZKSpringEssentialsPageHeader}}
{{ZKSpringEssentialsHeadingToc}}
 
  
===Purpose===
+
=Overview=  
Hide or un-hide certain parts of UI based on user's authorization
+
ZK Spring Security provides features to check a user's role and permissions so that you can determine whether to render certain parts of the UI based on the user's roles.
===Example===
 
This example is similar to the one introduced in "Add page based security using authorized roles" section except we have rewritten secured pages in ZUML to demonstrate how certain part of page be displayed or hidden based on user's authorization. You can run this example code by deploying ZK Spring Essentials examples web archive (download here) and either visiting http://localhost:8080/zkspringessentials/home1.zul directly or visiting the index page and clicking on Example 2 link. From home1.zul page you can navigate to secure pages by using the links from the bottom two rows. Once on the secure/index.zul  page based on logged in user's assigned role being ROLE_SUPERVISOR we  display relative message about secure/extreme/index.zul page access.
 
  
<gflash width="1180" height="480">Zkspringsec3.swf</gflash>
+
ZK Spring Security provides 2 ways to access user roles and permissions in a ZK application.  
  
===Configuration===
+
* '''SecurityUtil''' a java class providing static methods to be used in component, controller, and view model code
Since this example is similar to the one introduced in earlier sections you can follow the same configuration steps.
+
* '''Taglib functions''' and an implicit '''authentication''' object to perform permission checks conveniently in ZUL files (with EL-Expressions)
===ZK Spring Secuirty Utility Library===
+
 
For using security features in view layer you can utilize ZK Spring Security utility library which is defined as a tag library. You can use utility functions from this library with ZK components "if", "unless" attributes to show/hide/enable/disable some specific ZK compoents. To use this library simply declare a taglib directive at the start of your ZUML pages and you can use utility functions from this library as a part of your EL expressions.
+
=Using the Taglib in ZUL=
<source lang="xml">
+
 
<?taglib uri="http://www.zkoss.org/zkspring/security" prefix="sec"?>
+
In zul files the special attributes [[ZUML_Reference/ZUML/Attributes/if|if]] and [[ZUML_Reference/ZUML/Attributes/unless|unless]] are ideal candidates to render or omit certain parts of a zul file.
</source>
 
====In ZUML====
 
Lets take a look at secure/index.zul page to see how we can use the utility functions.
 
<source lang="xml">
 
<?page title="Secure Page"?>
 
<?taglib uri="http://www.zkoss.org/zkspring/security" prefix="sec"?>
 
<?variable-resolver class="org.zkoss.spring.DelegatingVariableResolver"?>
 
<window title="Secure Page" border="normal" width="500px" xmlns:n="http://www.zkoss.org/2005/zk/native">
 
<n:p>
 
This is a protected page. You can get to me if you've been remembered,
 
or if you've authenticated this session.
 
</n:p>
 
  
<zk if="${sec:isAllGranted('ROLE_SUPERVISOR')}">
+
After declaring the taglib the functions are available with the specified prefix.
    You are a supervisor! You can therefore see the <n:a href="extreme/index.zul">extremely secure page</n:a>.
 
</zk>
 
<zk unless="${sec:isAllGranted('ROLE_SUPERVISOR')}">
 
    You are NOT a supervisor! You can NOT see the <n:a href="extreme/index.zul">extremely secure page</n:a>.
 
</zk>
 
  
<n:h4>Properties obtained using implicit Object <n:b>"authentication"</n:b>.</n:h4>
+
<source lang="xml" highlight="1,4,9,12">
<grid>
+
<?taglib uri="http://www.zkoss.org/zkspring/security" prefix="sec"?>
    <columns>
+
<zk>
        <column label="Expression"/>
 
        <column label="Value" width="50px"/>
 
    </columns>
 
    <rows>
 
        <row><label value="authentication.name"/>${authentication.name}</row>
 
        <row><label value="authentication.principal.username"/>${authentication.principal.username}</row>
 
        <row><label value="authentication.principal.enabled"/>${authentication.principal.enabled}</row>
 
        <row><label value="authentication.principal.accountNonLocked"/>${authentication.principal.accountNonLocked}</row>
 
    </rows>
 
</grid>
 
<separator bar="true"></separator>
 
<button label="Home" href="../home1.zul"/>
 
<button label="Logout" href="../j_spring_security_logout"/>
 
</window>
 
</source>
 
  
 +
  <div if="${sec:isAllGranted('ROLE_SUPERVISOR')}">
 +
    This div and all child components are only displayed for user with the SUPERVISOR ROLE
 +
    <listbox .../>
 +
  </div>
  
The expression "sec:isAllGranted('role1,role2, ...')" will check whether the currently authenticated user has ''ALL'' roles specified in the isAllGranted() function and return true or false. Then according to the if/unless condition statement, the corresponding part of the page is thus rendered. You can also provide such expression to other ZK components. e.g. if a button shall only show to a supervisor user:
+
  <button if="${sec:isAnyGranted('ROLE_TELLER,ROLE_ACCOUNTANT')}"
 +
    label="For TELLERs and ACCOUNTANTs only" >
  
<source lang="xml" >
+
  <zk if="${sec:isNoneGranted('ROLE_TRAINEE,ROLE_ROOKIE')}">
<button label="Transfer Money" if="${sec:isAllGranted('ROLE_SUPERVISOR')}" .../>
+
    TRAINEES and ROOKIES won't see this.
 +
  </zk>
 +
</zk>
 
</source>
 
</source>
  
Or if you just want to disable the button but still visible to non-supervisor user.
+
As in all zul pages, the taglib function can also be used in a component's attributes. For example, to disable a button according to a role:
  
 
<source lang="xml">
 
<source lang="xml">
Line 67: Line 39:
 
</source>
 
</source>
  
'''Functions of ZK Spring Security Utitlity Library (org.zkoss.spring.security.SecurityUtil)''':
+
Available functions as implemented in ([https://www.zkoss.org/javadoc/latest/zkspring-security/org/zkoss/spring/security/SecurityUtil.html org.zkoss.spring.security.SecurityUtil]):
  
<ul>
+
* <code>boolean isNoneGranted(String authorities)</code>: Return true if the authenticated principal is granted NONE of the roles in the specified authorities.
<li>''boolean isNoneGranted(String authorities)'': Return true if the authenticated principal is granted NONE of the roles in the specified authorities.</li>
+
* <code>boolean isAllGranted(String authorities)</code>: Return true if the authenticated principal is granted ALL of the roles in the specified authorities.
<li>''boolean isAllGranted(String authorities)'': Return true if the authenticated principal is granted ALL of the roles in the specified authorities.</li>
+
* <code>boolean isAnyGranted(String authorities)</code>: Return true if the authenticated principal is granted ANY of the roles in the specified authorities.
<li>''boolean isAnyGranted(String authorities)'': Return true if the authenticated principal is granted ANY of the roles in the specified authorities.</li>
+
* <code>boolean isAccessible(String hasPermission, Object domainObject)</code>: Return true if the current Authentication has one of the specified permissions to the presented domain object instance.
<li>''boolean isAccessible(String hasPermission, Object domainObject)'': Return true if the current Authentication has one of the specified permissions to the presented domain object instance.</li>
+
* <code>Authentication getAuthentication()</code>: Return current login Authentication (similar to implicit "authentication" object).
<li>''Authentication getAuthentication()'': Return currently login Authentication (similar to implicit "authentication" object).
 
</ul>
 
====In Java====
 
  
The example we have shown are all .zul pages. "What if I would like to construct my pages with pure Java?" you might ask. We actually provide a ''org.zkoss.spring.security.SecurityUtil'' class that you can call static methods to access all functions. e.g.
+
=Using <code>SecurityUtil</code>=
 +
 
 +
You can call the methods of ([https://www.zkoss.org/javadoc/latest/zkspring-security/org/zkoss/spring/security/SecurityUtil.html org.zkoss.spring.security.SecurityUtil]) in java code directly, to build the UI conditionally:
  
 
<source lang="java">
 
<source lang="java">
Line 88: Line 59:
 
</source>
 
</source>
  
===The Implicit "authentication" Object===
+
=The Implicit "authentication" Object=
We introduce a new ZK Spring Security implicit object, "authentication". When any user login(including anonymous login) and you can access to the associated Spring Security [http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/Authentication.html Authentication] object in EL expression, zscript, or ZK annotate data binding expression.
 
  
'''WebContent/secure/index.zul'''
+
The <code>DelegatingVariableResolver</code> adds an implicit object "authentication" which exposes Spring's current authentication object [https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/core/Authentication.html Authentication] to EL expressions. Depending on the type of the principal object you can access also nested properties.
<source lang="xml">
+
 
<?page title="Secure Page"?>
+
<source lang="xml" highlight="1,3,6,9,12">
...
 
 
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
 
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Secure Page" border="normal" width="500px" xmlns:n="http://www.zkoss.org/2005/zk/native">
+
<div>
 +
  <label value="authentication.name"/> = ${authentication.name}
 +
</div>
 +
<div>
 +
  <label value="authentication.principal.username"/> = ${authentication.principal.username}
 +
</div>
 +
<div>
 +
  <label value="authentication.principal.enabled"/>  = ${authentication.principal.enabled}
 +
</div>
 +
<div>
 +
  <label value="authentication.principal.accountNonLocked"/> = ${authentication.principal.accountNonLocked}
 +
</div>
 +
</source>
  
...
+
=Websocket / Server Push support=
  
<n:h4>Properties obtained using implicit Object <n:b>"authentication"</n:b>.</n:h4>
+
As WebSocket and asynchronous UI updates (via server push) don't always go through Spring Security's Filter chain (as no HTTP Request is sent/filtered), the SecurityContextHolder is not initialized in such cases. The result is, that Spring won't be able to perform authentication or authorization (role) checks.
<grid>
 
<columns>
 
<column label="Expression"/>
 
<column label="Value" width="50px"/>
 
</columns>
 
<rows>
 
<row><label value="authentication.name"/>${authentication.name}</row>
 
<row><label value="authentication.principal.username"/>${authentication.principal.username}</row>
 
<row><label value="authentication.principal.enabled"/>${authentication.principal.enabled}</row>
 
<row><label value="authentication.principal.accountNonLocked"/>${authentication.principal.accountNonLocked}</row>
 
</rows>
 
</grid>
 
  
...
+
To achieve better integration the [https://github.com/zkoss/zkspring/blob/master/zkspring-security/src/main/java/org/zkoss/spring/init/SecurityContextAwareExecutionListener.java SecurityContextAwareExecutionListener] (an ExecutionInit/Cleanup-Listener) is added by default to fill the SecurityContextHolder from the current Session during UI updates.
  
</window>
+
This listener is enabled by default and can be disabled by setting the library property '''org.zkoss.spring.init.SecurityContextAwareExecutionListener.enabled''' to '''false'''.
</source>
 
  
As you can see in the example code. Provides the variable resolver then we can access the "authentication" implicit object.
 
<source lang="xml">
 
<?variable-resolver class="org.zkoss.spring.DelegatingVariableResolver"?>
 
</source>
 
 
You can use the intuitive "a.b.c" form to access properties of the Authentication object in EL expression.
 
 
<source lang="xml">
 
${authentication.principal.username}
 
</source>
 
  
=Version History=
 
{{LastUpdated}}
 
{| border='1px' | width="100%"
 
! Version !! Date !! Content
 
|-
 
| &nbsp;
 
| &nbsp;
 
| &nbsp;
 
|}
 
 
{{ZKSpringEssentialsPageFooter}}
 
{{ZKSpringEssentialsPageFooter}}

Latest revision as of 09:20, 13 December 2022

Add Security in the View Layer



Overview

ZK Spring Security provides features to check a user's role and permissions so that you can determine whether to render certain parts of the UI based on the user's roles.

ZK Spring Security provides 2 ways to access user roles and permissions in a ZK application.

  • SecurityUtil a java class providing static methods to be used in component, controller, and view model code
  • Taglib functions and an implicit authentication object to perform permission checks conveniently in ZUL files (with EL-Expressions)

Using the Taglib in ZUL

In zul files the special attributes if and unless are ideal candidates to render or omit certain parts of a zul file.

After declaring the taglib the functions are available with the specified prefix.

<?taglib uri="http://www.zkoss.org/zkspring/security" prefix="sec"?>
<zk>

  <div if="${sec:isAllGranted('ROLE_SUPERVISOR')}">
    This div and all child components are only displayed for user with the SUPERVISOR ROLE
    <listbox .../>
  </div>

  <button if="${sec:isAnyGranted('ROLE_TELLER,ROLE_ACCOUNTANT')}" 
     label="For TELLERs and ACCOUNTANTs only" >

  <zk if="${sec:isNoneGranted('ROLE_TRAINEE,ROLE_ROOKIE')}">
     TRAINEES and ROOKIES won't see this.
  </zk>
</zk>

As in all zul pages, the taglib function can also be used in a component's attributes. For example, to disable a button according to a role:

<button label="Transfer Money" disabled="${sec:isNoneGranted('ROLE_SUPERVISOR')}" .../>

Available functions as implemented in (org.zkoss.spring.security.SecurityUtil):

  • boolean isNoneGranted(String authorities): Return true if the authenticated principal is granted NONE of the roles in the specified authorities.
  • boolean isAllGranted(String authorities): Return true if the authenticated principal is granted ALL of the roles in the specified authorities.
  • boolean isAnyGranted(String authorities): Return true if the authenticated principal is granted ANY of the roles in the specified authorities.
  • boolean isAccessible(String hasPermission, Object domainObject): Return true if the current Authentication has one of the specified permissions to the presented domain object instance.
  • Authentication getAuthentication(): Return current login Authentication (similar to implicit "authentication" object).

Using SecurityUtil

You can call the methods of (org.zkoss.spring.security.SecurityUtil) in java code directly, to build the UI conditionally:

if (SecurityUtil.isAllGranted("ROLE_SUPERVISOR")) {
	Button btn = new Button();
	...
	btn.setParent(win);
}

The Implicit "authentication" Object

The DelegatingVariableResolver adds an implicit object "authentication" which exposes Spring's current authentication object Authentication to EL expressions. Depending on the type of the principal object you can access also nested properties.

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<div>
  <label value="authentication.name"/> = ${authentication.name}
</div>
<div>
  <label value="authentication.principal.username"/> = ${authentication.principal.username}
</div>
<div>
  <label value="authentication.principal.enabled"/>  = ${authentication.principal.enabled}
</div>
<div>
  <label value="authentication.principal.accountNonLocked"/> = ${authentication.principal.accountNonLocked}
</div>

Websocket / Server Push support

As WebSocket and asynchronous UI updates (via server push) don't always go through Spring Security's Filter chain (as no HTTP Request is sent/filtered), the SecurityContextHolder is not initialized in such cases. The result is, that Spring won't be able to perform authentication or authorization (role) checks.

To achieve better integration the SecurityContextAwareExecutionListener (an ExecutionInit/Cleanup-Listener) is added by default to fill the SecurityContextHolder from the current Session during UI updates.

This listener is enabled by default and can be disabled by setting the library property org.zkoss.spring.init.SecurityContextAwareExecutionListener.enabled to false.



Last Update : 2022/12/13

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.