0

how does the "right management" work in terrytornado 's sample application?

asked 2009-09-01 16:12:57 +0800

df2334 gravatar image df2334
48 1

updated 2009-09-01 16:13:50 +0800

Hi

I've seen terry's sample zk application and it's really fabulous.

Does anyone know how does that "right management" part work?

Terry, if you see this , could you please explain how it works for me??

ZK user manual only shows that the configuration of authrozation and authentications are hard coded in the applicationContext-security.xml file.

With your one, seems that everything(role, intercept event) is in the database and your application just pulls out the data at run time and does the security check based on this data .

Could you explain how did you setup your applicationContext-security.xml file so that you could let the spring Security retrieve data from database at run time??

thanks

delete flag offensive retag edit

29 Replies

Sort by » oldest newest

answered 2009-09-01 20:28:02 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2009-09-01 23:00:57 +0800

Hi df2334

i will tomorrow write a little bit more about it and store it in the readme.txt in the docs folder.
So you must refresh this file from the subversion repository. Some is explained in the welcome.zul at
startup the sample app. Go to the Panel 'whats in it and sample Data' and click the 'Administration' tab.

So, i'm using a borderlayout in my index.zul (the main page) and put all other called zul-pages in the
center area of it, i have an other working like the normal jsf/jsp apps. As a result i'm always have the
same URL: ~/index.zul
Therefore i cannot work with an url-based security management like the most 'spring' samples shows.

 
   ...and your application just pulls out the data at run time and does the security check 

yes and no.

In Spring-Security a 'right' is only a String. If it exists in the rights (so called grantedRights) for a user
than the user have the right for this.
The logic is following:
1. The user try to logged in.
2. If he's veryfied than the logic looks for the rights that the user have by
going through the security section tree down to get all rights and stores them in a grantedRights List.
This is done ONE time for each user at the log in process and comes out of the database.

User (have)
        \-- Roles (have)
                     \-- Role-Groups (have) extended for my needs
                                        \-- Group-Rights (have) extended for my needs
                                                            \-- Rights 


For the applicationContext-security.xml you must checkout the sample app sources. This file is very well documented.
Look at the /docs/readme.txt for the right name of this file in the sample app.

regards
Stephan

The checkout URL for the whole projects (frontend / backend) you will find here in the ZKoss-Forum category 'Announce'.
There are other ZKoss-Forum categories like 'Help' :-)

PS: Help to prevent the global warming by writing cool software.

link publish delete flag offensive edit

answered 2009-09-02 01:21:42 +0800

df2334 gravatar image df2334
48 1

updated 2009-09-02 01:23:36 +0800

Hi, Stephan

Thanks for your reply.
May be i didn't bring my question clearly.

I am more concerned about the technique of how did you setup your xml config file so that it can read data from the database

All examples I've seen from Spring security and Zk tutorials , the authentications and authorizations are "Hard coded" in the xml file. For example, in the following code

    <http auto-config='true'>2
        <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />3
        <intercept-url pattern="/**" access="ROLE_USER" />
    </http>

    <authentication-provider>
        <user-service>
            <user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />4
            <user name="user" password="user" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>

User account information ,password, authorities are all "hard coded" in this xml file.

I've searched on google for tutorial and i now know how to let Spring Security automatically connect to the database and read user
account information and authorities from there. I can let SPring security now read information from database by using the following
setup

    <authentication-provider>
        <jdbc-user-service data-source-ref="dataSource"
            1users-by-username-query="select username,password,status as enabled
                                         from user
                                        where username=?"
            2authorities-by-username-query="select u.username,r.name as authority
                                             from user u
                                             join user_role ur
                                               on u.id=ur.user_id
                                             join role r
                                               on r.id=ur.role_id
                                            where u.username=?"/>
    </authentication-provider>


Now it works all fine with URL based interceptions, when it comes to ZK event interception using spring security,
it becomes the pain of my head.
The trick is that ZK event interception uses different configuration setup format

<zksp:zk-event login-template-close-delay="5">
<zksp:intercept-event event="onClick" path="//**/btn_*" access="ROLE_TELLER"/>
<zksp:intercept-event path="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
</zksp:zk-event>

I have no idea of how to let it read data from database automatically, neither ZK user manual nor Spring security
have any information are related to my question.

So please help me with this.

Thanks heaps

link publish delete flag offensive edit

answered 2009-09-02 12:08:17 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2009-09-02 13:26:29 +0800

Have you downloaded the sample app consists of their two projects?

Here are the security xml:
You can see that i have declared an other authentication-provider.

<?xml version="1.0" encoding="UTF-8"?>

	<!-- Spring namespace-based configuration -->

<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:zksp="http://www.zkoss.org/2008/zkspring"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd
						http://www.springframework.org/schema/aop   
						http://www.springframework.org/schema/aop/spring-aop-2.0.xsd                        
                        http://www.zkoss.org/2008/zkspring http://www.zkoss.org/2008/zkspring/zkspring.xsd">



	<!-- Enable the @Secured annotation to secure service layer methods -->
	<global-method-security secured-annotations="enabled" />

	<http auto-config="true">

		<!-- ###  If we have our own LoginPage. So we must    ### -->
		<!-- ###     tell Spring the name and the place.      ### -->
		<!-- ###     In our case we take the same page        ### -->
		<!-- ###     for a error message by a failure.        ### -->
		<!-- ### Further the page after a successfully login. ### -->
		<form-login login-page="/zkloginDialog.zul"
			authentication-failure-url="/zkloginDialog.zul?login_error=1"
			default-target-url="/pages/index.zul" />

		<!-- ###   Tell Spring where it goes after logout.    ### -->
		<!-- ###          logout-url is a action url.         ### -->
		<logout logout-url="/j_spring_logout" logout-success-url="/index.zul" />

		<!-- ### Define the pages that are to be intercepted  ### -->
		<!-- ### It is parsed from top to bottom. Means that  ### -->
		<!-- ### the most specific pattern is standing on TOP ### -->
		<!-- ###         and the CATCH ALL is on BOTTOM!      ### -->
		<intercept-url pattern="/pages/**" access="IS_AUTHENTICATED_REMEMBERED" />
		<intercept-url pattern="/WEB-INF/pages/**" access="IS_AUTHENTICATED_REMEMBERED" />

		<!-- ### The root page is accessible by everyone but  ### -->
		<!-- ###    internally spring makes a login and       ### -->
		<!-- ###     this user becames a UserDetails          ### -->
		<!-- ###   (in there are the ip-address and others)   ### -->
		<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />

		<!-- ###           Per user one session !!            ### -->
		<concurrent-session-control max-sessions="1" />
	</http>

	<!-- ###   We define the kind of authentification with a  ### -->
	<!-- ###          so called authentication-provider       ### -->
	<!-- ###   So we have our users stored in a DB we use     ### -->
	<!-- ###   our own user-service class and point to her.   ### -->
	<authentication-provider user-service-ref="myUserDetailsService">
	</authentication-provider>



	<!-- ###   The Implementation of the Interface            ### -->
	<!-- ###      UserDetailService for the logged in         ### -->
	<!-- ###              user and his rights                 ### -->
	<beans:bean id="myUserDetailsService" class="de.forsthaus.zksample.policy.PolicyManager">
		<beans:property name="userService" ref="userService" />
	</beans:bean>



	<!-- ###      Here, only for showing in the console       ### -->
	<!-- ###              that we catches the events.         ### -->
	<zksp:zk-event login-template-close-delay="5">
		<zksp:intercept-event path="//**/btn_*" event="onClick"
			access="IS_AUTHENTICATED_REMEMBERED" />
		<zksp:intercept-event path="/**" event="onClick"
			access="IS_AUTHENTICATED_ANONYMOUSLY" />
	</zksp:zk-event>


	<!-- ###   This aspect call automatically the methode     ### -->
	<!-- ###   'loginLogging' which is for writing a log for  ### -->
	<!-- ###   all successfully and failed logins, if a       ### -->
	<!-- ###   methode is called that handles the             ### -->
	<!-- ###    Authentication.                               ### -->
	<beans:bean id="LoginLoggingPolicyService"
		class="de.forsthaus.zksample.policy.LoginLoggingPolicyService">
		<beans:property name="loginLoggingService" ref="loginLoggingService" />
	</beans:bean>

	<aop:config>
		<aop:aspect id="LoginLoggingAspect" ref="LoginLoggingPolicyService">
			<aop:pointcut id="authPointcut"
				expression="execution(public org.springframework.security.Authentication org.springframework.security.providers.AuthenticationProvider.authenticate(org.springframework.security.Authentication))" />
			<aop:around pointcut-ref="authPointcut" method="loginLogging" />
		</aop:aspect>
	</aop:config>

</beans:beans>

The important point is the implementation of the Spring-Security Interface UserDetailService
which you can find in my app in the PolicyManager class. There is only ONE methode to implement.

@Override
public UserDetails loadUserByUsername(String userId) {

public class PolicyManager implements UserDetailsService, Serializable {

	private static final long serialVersionUID = 1L;
	private transient final static Logger logger = Logger.getLogger(PolicyManager.class);

	private transient UserService userService;

	public SecUser getUserByLoginname(final String userName) {
		return getUserService().getUserByLoginname(userName);
	}

	@Override
	public UserDetails loadUserByUsername(String userId) {

		SecUser user = null;
		GrantedAuthority[] grantedAuthorities = null;
		try {
			user = getUserByLoginname(userId);

			if (user == null) {
				throw new UsernameNotFoundException("Invalid User");
			}

			// TEST
			String context = user.getUsrLocale(); // i.e. 'en_EN' or 'de_DE'

			// if (!StringUtils.isEmpty(context)) {
			// Labels.register(new GeneralLabelLocator(context));
			// }

			grantedAuthorities = getGrantedAuthority(user);
		} catch (NumberFormatException e) {
			throw new DataRetrievalFailureException("Cannot loadUserByUsername userId:" + userId + " Exception:" + e.getMessage(), e);
		}

		UserDetails userDetails = new UserImpl(user, grantedAuthorities);

		if (logger.isDebugEnabled()) {
			logger.debug("Rechte für '" + user.getUsrLoginname() + "' (ID: " + user.getUsrId() + ") ermittelt. ("
					+ Arrays.toString(grantedAuthorities) + ") [" + this + "]");

			for (GrantedAuthority grantedAuthority : grantedAuthorities) {
				logger.debug(grantedAuthority.getAuthority());
			}
		}

		return userDetails;

	}

	private GrantedAuthority[] getGrantedAuthority(SecUser user) {

		List<SecRight> rights = getUserService().getRightsByUser(user);

		GrantedAuthority[] grantedAuthorities = null;
		grantedAuthorities = new GrantedAuthority[rights.size()];

		for (int i = 0; i < rights.size(); i++) {

			SecRight right = rights.get(i);

			GrantedAuthority authority = new GrantedAuthorityImpl(right.getRigName());
			grantedAuthorities<i > = authority;
		}

		return grantedAuthorities;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void test() {
		System.out.println("PolicyManager.test() -> " + loadUserByUsername("user"));
	}
}


The rights i get from the database with the following code which you can find in the backend project.

UserServiceImpl.java

	@Override
	public List<SecRight> getRightsByUser(SecUser user) {

		List rightList = new ArrayList<SecRight>();

		// 1. erst die zum User zugeteilten Rollen ermitteln
		// 1. First get the roles that are attached to a user
		List<SecRole> listRoles = new ArrayList<SecRole>();
		listRoles = getRolesByUser(user);

		if (logger.isDebugEnabled()) {
			if (listRoles != null) {
				for (SecRole secRole : listRoles) {
					logger.info(secRole.getRolShortdescription());
				}
			}
		}

		// 2. die zu den Rollen die zugehörigen Gruppen ermitteln
		// 2. get the groups that belongs to the roles
		List<SecGroup> listGroup = new ArrayList<SecGroup>();

		if (listRoles != null) {
			for (SecRole role : listRoles) {

				List<SecGroup> tmpListGroup = new ArrayList<SecGroup>();
				tmpListGroup = getSecRolegroupDAO().getGroupsByRole(role);

				if (tmpListGroup != null) {
					for (SecGroup secGroup : tmpListGroup) {
						listGroup.add(secGroup);
					}
				}

			}
		}

		if (logger.isDebugEnabled()) {
			if (listGroup != null) {
				for (SecGroup secGroup : listGroup) {
					logger.info(secGroup.getGrpShortdescription());
				}
			}
		}

		// 3. zu den Gruppen die zugeordneten Rechte ermitteln
		// 3. get the rights that belongs to the groups
		List<SecRight> listRight = new ArrayList<SecRight>();

		if (listGroup != null) {
			for (SecGroup group : listGroup) {

				List<SecRight> tmpListRight = new ArrayList<SecRight>();
				tmpListRight = getSecGrouprightDAO().getRightsByGroup(group);

				if (tmpListRight != null) {
					for (SecRight secRight : tmpListRight) {
						listRight.add(secRight);
					}
				}
			}
		}

		if (logger.isDebugEnabled()) {
			if (listRight != null) {
				for (SecRight secRight : listRight) {
					logger.info(secRight.getRigName());
				}
			}
		}

		// 4. Doppelte Rechte unterdrücken
		// 4. filter double rights out
		if (listRight != null) {

			List decorateList = SetUniqueList.decorate(rightList);
			for (int i = 0; i < listRight.size(); i++) {
				decorateList.add(listRight.get(i));
			}
		}

		if (logger.isDebugEnabled()) {
			logger.info("--> Decorated List");
			if (rightList != null) {
				for (SecRight secRight : (List<SecRight>) rightList) {
					logger.info(secRight.getRigName());
				}
			}
		}

		return rightList;
	}

regards
Stephan

link publish delete flag offensive edit

answered 2009-09-03 00:29:23 +0800

df2334 gravatar image df2334
48 1

Hi, Stephan

thanks for your answer, I've played your application a few more times and now it looks to me that the right management is built solely by developers and does not go through "Spring Security", am I right? So users are only able to see components which belong to their right group, which is controlled by your application and not by Spring Security.

I have a question , if a user tries to access a individual zul component page, will it be checked by Spring Security?

Thanks

link publish delete flag offensive edit

answered 2009-09-03 14:25:05 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2009-09-03 14:27:33 +0800

Hmmmmmmmmmmmmmm,

OK let me explain a little deeper.

the destination of the spring and spring-security frameworks is to made 'enterprise' application developing easier.
So you must not take all of them. You can take these pieces that you mean that is the best fit for your needs.

It's depending on how do you build your application. So my intention was to build a prototyp that should go the ajax way.
Means that i want not to load the whole page again, if i will load only a piece of them new.
So i'm using a borderlayout in the whole time in the main index.zul Means that on left side in it is the menu
and in the center area there are the contents of the several modules like customers, orders, articles,...

That's nice but it's all time the same URL. So i cannot use a piece of the spring-security so called the Url-based security mechanism.
I must secure the content area in an other wise. So i do it in creating the allowed menu entries.

does not go through "Spring Security",

If you mean with 'go through' the listeners and filters. Yes, in this case i do it without the url-based filter.
because i've explained it cannot works with a main borderlayout for the several areas.

I have a question , if a user tries to access a individual zul component page, will it be checked by Spring Security?

You can try to input a page directly in the browser. you will fail. Spring-Security looks for two pages:
the entry index.zul and the application index.zul On all others you have only access over the application.
So it will be checked by Spring-sec. But in an other way that most simple samples shows.

Further the log-in mechanism and the grantedRights for a user is spring-managed.

I will implement the outstanding event-securing. That is missing at time. I have started a new thread because it's seems
that there is a problem with accesing the events of dynamic created components like rows in a listbox.
So i know not the component path for let spring comparing them with a secured-event-list.

Hope i can help a little bit.

regards
Stephan

link publish delete flag offensive edit

answered 2010-06-05 11:11:34 +0800

joredva gravatar image joredva
69

Hi terrytornado
Regards
First of all thanks for your great contribution please help with a question.
I try to login to the application as a user and I have this error "Login failed. Please try again.
Reason: User account is locked
"
The user administrator and has full permissions.
UserImpl In class I can see that the field user.isUsrAccountnonlocked () equals TRUE

Please show me what happens ...?

Sorry for my little English

link publish delete flag offensive edit

answered 2010-06-06 06:02:44 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

Hmmmmm,
is this behaviour after creating a new User account? Can be that we must set a default value to the SecUser.usrAccountnonlocked when we declare the instance vars.
I'll check this next week and update the backend project.

By testing if i uncheck the 'Account not locked' than i became this errorMessage. That's right.
If i check 'Account not locked' than it goes further. That's right.

best
Stephan

link publish delete flag offensive edit

answered 2010-06-06 06:13:00 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

Modified and comited


/**
* Model class for the <b>SecUser table</b>.<br>
*
* @author bbruhns
* @author sgerth
*/
public class SecUser implements java.io.Serializable, Entity {

private static final long serialVersionUID = -8443234918260997954L;

private long id = Long.MIN_VALUE;
private int version;
private String usrLoginname;
private String usrPassword;
private String usrLastname;
private String usrFirstname;
private String usrEmail;
private String usrLocale;
private boolean usrEnabled = true;
private boolean usrAccountnonexpired = true;
private boolean usrCredentialsnonexpired = true;
private boolean usrAccountnonlocked = true;
private String usrToken;
private Set<SecUserrole> secUserroles = new HashSet<SecUserrole>(0);

link publish delete flag offensive edit

answered 2010-06-06 07:04:40 +0800

joredva gravatar image joredva
69

Thank you for answering
This problem is resolved.

I use JPA classes and have migrated to JPASearchSupport JPASearchSupportImpl the classes HibernateSearchSupportImpl HibernateSearchSupport to use.
In the file applicationContext-hibernate.xml have changed:

<!-- ====================================================== -->
<!-- Search class from Hibernate-Generic-DAO framework -->
<!-- ====================================================== -->
<bean id="hibernateSearchSupport"
class="de.forsthaus.backend.dao.impl.HibernateSearchSupportImpl">
<property name="sessionFactory" ref="sessionFactory" />
<property name="hibernateSearchProcessor">
<bean class="com.trg.search.hibernate.HibernateSearchProcessor"
factory-method="getInstanceForSessionFactory">
<constructor-arg ref="sessionFactory" />
</bean>
</property>
</bean>
For
<!-- ====================================================== -->
<!-- Search class from JPA-Generic-DAO framework -->
<!-- ====================================================== -->
<bean id="jpaSearchSupport"
class="de.forsthaus.backend.dao.impl.JPASearchSupportImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaSearchProcessor">
<bean class="com.trg.search.jpa.JPASearchProcessor">
</bean>
</property>
</bean>

And I have this error
2010-06-06 06:57:53,359 ERROR ContextLoader M - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaSearchSupport' defined in ServletContext resource [/WEB-INF/config/applicationContext-jpa.xml]: Cannot create inner bean 'com.trg.search.jpa.JPASearchProcessor#676e3f' of type [com.trg.search.jpa.JPASearchProcessor] while setting bean property 'jpaSearchProcessor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.trg.search.jpa.JPASearchProcessor#676e3f' defined in ServletContext resource [/WEB-INF/config/applicationContext-jpa.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.trg.search.jpa.JPASearchProcessor]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.trg.search.jpa.JPASearchProcessor.<init>()
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:281)

Could you tell me how it should configure this ..?
Gracias

link publish delete flag offensive edit

answered 2010-06-06 08:25:07 +0800

terrytornado gravatar image terrytornado flag of Germany
9393 3 7 16
http://www.oxitec.de/

updated 2010-06-06 08:31:14 +0800

Hmmmm,

the constructor requires a MetaDataUtil instance.

Please read the Doc here. You can write a question to David about the correct Spring configuration.
Please let us know

-------------
Edit:

<p>This class is designed to be used as a singleton. The constructor requires a
* MetadataUtil instance. Each MetadataUtil instance is typically associated
* with a single persistence unit (i.e. EntityManagerFactory). A
* JPASearchProcessor can only be used with EntityManagers that are associated
* with the same persistence unit as the MetadataUtil. If an application has
* multiple persistence units, it will need to have multiple corresponding
* Search Processors.
*
* @author dwolverton
*/
public class JPASearchProcessor extends BaseSearchProcessor {

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2009-09-01 16:12:57 +0800

Seen: 2,200 times

Last updated: Jul 28 '10

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More