From 93022ba559be08c8463a6a8cf1c1be87ac505345 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 9 Apr 2013 07:33:32 +0200 Subject: [PATCH] [Major] major rewrite of the privilege validation. Now the PrivilegeContext object is central and once the user logged in, this object is bound to a ThreadLocal. From then there is no further need to interact with the PrivilegeHandler - this allows for authenticated users to get a remote copy of the PrivilegeContext so that on a remote client, the user can check for permissions, without having to do the round trip to the server. A code review of this change would be good, but preliminary tests show that it works. A test should now be implemented to check if getting a remote copy also allows for authorization. --- config/Model.xml | 55 +++ config/Privilege.xml | 2 +- config/PrivilegeModel.xml | 42 +- pom.xml | 2 +- .../handler/DefaultPrivilegeHandler.java | 392 ++++++--------- .../privilege/handler/PersistenceHandler.java | 4 +- .../privilege/handler/PrivilegeHandler.java | 63 +-- .../privilege/handler/SystemUserAction.java | 10 +- .../helper/CertificateThreadLocal.java | 48 -- .../privilege/i18n/PrivilegeMessages.java | 46 ++ .../i18n/PrivilegeMessages.properties | 6 + .../eitchnet/privilege/model/Certificate.java | 28 +- .../eitchnet/privilege/model/IPrivilege.java | 92 ++++ .../privilege/model/PrivilegeContext.java | 161 ++++++ .../privilege/model/PrivilegeRep.java | 77 ++- .../privilege/model/Restrictable.java | 7 +- .../ch/eitchnet/privilege/model/RoleRep.java | 13 + .../ch/eitchnet/privilege/model/UserRep.java | 28 ++ .../internal/PrivilegeContainerModel.java | 4 + .../{Privilege.java => PrivilegeImpl.java} | 123 +++-- .../privilege/model/internal/Role.java | 40 +- .../privilege/model/internal/Session.java | 191 -------- .../privilege/model/internal/User.java | 9 +- .../privilege/policy/DefaultPrivilege.java | 66 ++- .../privilege/policy/PrivilegePolicy.java | 15 +- .../xml/PrivilegeModelDomWriter.java | 5 +- .../xml/PrivilegeModelSaxReader.java | 9 +- .../privilege/test/PrivilegeTest.java | 463 +++++++++--------- .../ch/eitchnet/privilege/test/XmlTest.java | 18 +- .../test/model/TestSystemUserAction.java | 26 +- .../test/model/TestSystemUserActionDeny.java | 20 +- 31 files changed, 1061 insertions(+), 1004 deletions(-) create mode 100644 config/Model.xml delete mode 100644 src/main/java/ch/eitchnet/privilege/helper/CertificateThreadLocal.java create mode 100644 src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.java create mode 100644 src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.properties create mode 100644 src/main/java/ch/eitchnet/privilege/model/IPrivilege.java create mode 100644 src/main/java/ch/eitchnet/privilege/model/PrivilegeContext.java rename src/main/java/ch/eitchnet/privilege/model/internal/{Privilege.java => PrivilegeImpl.java} (63%) delete mode 100644 src/main/java/ch/eitchnet/privilege/model/internal/Session.java diff --git a/config/Model.xml b/config/Model.xml new file mode 100644 index 000000000..74dabc4f4 --- /dev/null +++ b/config/Model.xml @@ -0,0 +1,55 @@ + + + + + + + + + + true + + + + + + true + + + true + + + + + + + + + Application + Administrator + ENABLED + en_GB + + PrivilegeAdmin + AppUser + + + + + + + + + System User + Administrator + SYSTEM + en_GB + + system_admin_privileges + + + + + + + diff --git a/config/Privilege.xml b/config/Privilege.xml index b37070a5a..20eda653e 100644 --- a/config/Privilege.xml +++ b/config/Privilege.xml @@ -39,7 +39,7 @@ along with Privilege. If not, see . - + diff --git a/config/PrivilegeModel.xml b/config/PrivilegeModel.xml index 4c788b66e..a58e6830c 100644 --- a/config/PrivilegeModel.xml +++ b/config/PrivilegeModel.xml @@ -1,26 +1,10 @@ - + @@ -39,7 +23,7 @@ along with Privilege. If not, see . - + System User Administrator @@ -48,7 +32,7 @@ along with Privilege. If not, see . system_admin_privileges - + @@ -58,20 +42,20 @@ along with Privilege. If not, see . - + true - + - + true - + true - + hello diff --git a/pom.xml b/pom.xml index bddc78dba..2d601786a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ ch.eitchnet ch.eitchnet.privilege jar - 0.1.0-SNAPSHOT + 0.2.0-SNAPSHOT ch.eitchnet.privilege https://github.com/eitch/ch.eitchnet.privilege diff --git a/src/main/java/ch/eitchnet/privilege/handler/DefaultPrivilegeHandler.java b/src/main/java/ch/eitchnet/privilege/handler/DefaultPrivilegeHandler.java index 0235341b0..43691ca2a 100644 --- a/src/main/java/ch/eitchnet/privilege/handler/DefaultPrivilegeHandler.java +++ b/src/main/java/ch/eitchnet/privilege/handler/DefaultPrivilegeHandler.java @@ -19,6 +19,7 @@ */ package ch.eitchnet.privilege.handler; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -35,14 +36,14 @@ import ch.eitchnet.privilege.base.AccessDeniedException; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.helper.ClassHelper; import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.IPrivilege; +import ch.eitchnet.privilege.model.PrivilegeContext; import ch.eitchnet.privilege.model.PrivilegeRep; -import ch.eitchnet.privilege.model.Restrictable; import ch.eitchnet.privilege.model.RoleRep; import ch.eitchnet.privilege.model.UserRep; import ch.eitchnet.privilege.model.UserState; -import ch.eitchnet.privilege.model.internal.Privilege; +import ch.eitchnet.privilege.model.internal.PrivilegeImpl; import ch.eitchnet.privilege.model.internal.Role; -import ch.eitchnet.privilege.model.internal.Session; import ch.eitchnet.privilege.model.internal.User; import ch.eitchnet.privilege.policy.PrivilegePolicy; @@ -72,7 +73,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { private static final String PARAM_AUTO_PERSIST_ON_PASSWORD_CHANGE = "autoPersistOnPasswordChange"; /** - * log4j logger + * slf4j logger */ protected static final Logger logger = LoggerFactory.getLogger(DefaultPrivilegeHandler.class); @@ -82,14 +83,9 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { private long lastSessionId; /** - * This map stores certificates for system users as a cache + * Map keeping a reference to all active sessions */ - private Map systemUserCertificateMap; - - /** - * Map keeping a reference to all active sessions with their certificates - */ - private Map sessionMap; + private Map privilegeContextMap; /** * Map of {@link PrivilegePolicy} classes @@ -132,41 +128,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { return user.asUserRep(); } - /** - *

- * This method instantiates a {@link PrivilegePolicy} object from the given policyName. The {@link PrivilegePolicy} - * is not stored in a database. The privilege name is a class name and is then used to instantiate a new - * {@link PrivilegePolicy} object - *

- * - * @param policyName - * the class name of the {@link PrivilegePolicy} object to return - * - * @return the {@link PrivilegePolicy} object - * - * @throws PrivilegeException - * if the {@link PrivilegePolicy} object for the given policy name could not be instantiated - */ - private PrivilegePolicy getPolicy(String policyName) { - - // get the policies class - Class policyClazz = this.policyMap.get(policyName); - if (policyClazz == null) { - return null; - } - - // instantiate the policy - PrivilegePolicy policy; - try { - policy = ClassHelper.instantiateClass(policyClazz); - } catch (Exception e) { - throw new PrivilegeException("The class for the policy with the name " + policyName + " does not exist!" - + policyName, e); - } - - return policy; - } - @Override public List queryUsers(UserRep selectorRep) { @@ -377,8 +338,15 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { } // create new role with the additional privilege - Privilege newPrivilege = new Privilege(privilegeRep); - Map privilegeMap = new HashMap(role.getPrivilegeMap()); + IPrivilege newPrivilege = new PrivilegeImpl(privilegeRep); + // copy existing privileges + Set existingPrivilegeNames = role.getPrivilegeNames(); + Map privilegeMap = new HashMap(existingPrivilegeNames.size() + 1); + for (String name : existingPrivilegeNames) { + IPrivilege privilege = role.getPrivilege(name); + privilegeMap.put(name, privilege); + } + // add new one privilegeMap.put(newPrivilege.getName(), newPrivilege); Role newRole = new Role(role.getName(), privilegeMap); @@ -438,9 +406,11 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { if (!role.hasPrivilege(privilegeName)) throw new PrivilegeException("Role " + roleName + " does not have Privilege " + privilegeName); - // create new set of privileges with out the to remove privilege - Map newPrivileges = new HashMap(role.getPrivilegeMap().size() - 1); - for (Privilege privilege : role.getPrivilegeMap().values()) { + // create new set of privileges with out the to removed privilege + Set privilegeNames = role.getPrivilegeNames(); + Map newPrivileges = new HashMap(privilegeNames.size() - 1); + for (String name : privilegeNames) { + IPrivilege privilege = role.getPrivilege(name); if (!privilege.getName().equals(privilegeName)) newPrivileges.put(privilege.getName(), privilege); } @@ -666,7 +636,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { + " and can not login!"); // validate user has at least one role - if (user.getRoles().isEmpty()) { + Set userRoles = user.getRoles(); + if (userRoles.isEmpty()) { throw new PrivilegeException("User " + username + " does not have any roles defined!"); } @@ -678,15 +649,14 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { String sessionId = nextSessionId(); // create a new certificate, with details of the user - certificate = new Certificate(sessionId, username, authToken, authPassword, user.getLocale(), - new HashMap(user.getProperties())); + certificate = new Certificate(sessionId, System.currentTimeMillis(), username, authToken, authPassword, + user.getLocale(), new HashMap(user.getProperties())); - // create and save a new session - Session session = new Session(sessionId, username, authToken, authPassword, System.currentTimeMillis()); - this.sessionMap.put(sessionId, new CertificateSessionPair(session, certificate)); + PrivilegeContext privilegeContext = buildPrivilegeContext(certificate, user); + this.privilegeContextMap.put(sessionId, privilegeContext); // log - DefaultPrivilegeHandler.logger.info("User " + username + " authenticated: " + session); + DefaultPrivilegeHandler.logger.info("User " + username + " authenticated: " + certificate); } catch (RuntimeException e) { DefaultPrivilegeHandler.logger.error("User " + username + " Failed to authenticate: " @@ -700,6 +670,56 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { return certificate; } + /** + * Builds a {@link PrivilegeContext} for the given {@link User} and its {@link Certificate} + * + * @param certificate + * @param user + * + * @return + */ + private PrivilegeContext buildPrivilegeContext(Certificate certificate, User user) { + + Set userRoles = user.getRoles(); + Map privileges = new HashMap(); + Map policies = new HashMap(); + + // get a cache of the privileges and policies for this user + for (String roleName : userRoles) { + Role role = this.persistenceHandler.getRole(roleName); + Set privilegeNames = role.getPrivilegeNames(); + for (String privilegeName : privilegeNames) { + + // cache the privilege + if (privileges.containsKey(privilegeName)) + continue; + + IPrivilege privilege = role.getPrivilege(privilegeName); + if (privilege == null) { + throw new PrivilegeException(MessageFormat.format("The Privilege {0} does not exist for role {1}", + privilegeName, roleName)); + } + privileges.put(privilegeName, privilege); + + // cache the policy for the privilege + String policyName = privilege.getPolicy(); + if (policies.containsKey(policyName)) + continue; + + PrivilegePolicy policy = getPolicy(policyName); + if (policy == null) { + throw new PrivilegeException(MessageFormat.format( + "The Policy {0} does not exist for Privilege {1}", policyName, privilegeName)); + } + policies.put(policyName, policy); + } + } + + UserRep userRep = user.asUserRep(); + PrivilegeContext privilegeContext = new PrivilegeContext(userRep, certificate, privileges, policies); + return privilegeContext; + } + @Override public boolean invalidateSession(Certificate certificate) { @@ -707,10 +727,10 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { isCertificateValid(certificate); // remove registration - CertificateSessionPair certificateSessionPair = this.sessionMap.remove(certificate.getSessionId()); + PrivilegeContext privilegeContext = this.privilegeContextMap.remove(certificate.getSessionId()); // return true if object was really removed - boolean loggedOut = certificateSessionPair != null; + boolean loggedOut = privilegeContext != null; if (loggedOut) DefaultPrivilegeHandler.logger.info("User " + certificate.getUsername() + " logged out."); else @@ -718,136 +738,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { return loggedOut; } - /** - * Checks if the action is allowed by iterating the roles of the certificates user and then delegating to - * {@link #actionAllowed(Role, Restrictable)} - * - * @throws AccessDeniedException - * if the {@link Certificate} is not for a currently logged in {@link User} or if the user may not - * perform the action defined by the {@link Restrictable} implementation - * - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#actionAllowed(ch.eitchnet.privilege.model.Certificate, - * ch.eitchnet.privilege.model.Restrictable) - */ - @Override - public void actionAllowed(Certificate certificate, Restrictable restrictable) { - - // TODO What is better, validate from {@link Restrictable} to {@link User} or the opposite direction? - - // first validate certificate - isCertificateValid(certificate); - - // restrictable must not be null - if (restrictable == null) - throw new PrivilegeException("Restrictable may not be null!"); - - // get user object - User user = this.persistenceHandler.getUser(certificate.getUsername()); - if (user == null) { - throw new PrivilegeException( - "Oh boy, how did this happen: No User in user map although the certificate is valid!"); - } - - String privilegeName = restrictable.getPrivilegeName(); - - // now iterate roles and validate on policies - for (String roleName : user.getRoles()) { - - Role role = this.persistenceHandler.getRole(roleName); - if (role == null) { - DefaultPrivilegeHandler.logger.error("No role is defined with name " + roleName - + " which is configured for user " + user); - continue; - } - - // ignore if this role does not have the privilege - if (!role.hasPrivilege(privilegeName)) - continue; - - // if action is allowed, then break iteration as a privilege match has been made - if (actionAllowed(role, restrictable)) - return; - } - - throw new AccessDeniedException("User " + user.getUsername() + " does not have Privilege " + privilegeName - + " needed for Restrictable " + restrictable.getClass().getName()); - } - - /** - * Checks if the {@link RoleRep} has access to the {@link Restrictable} by delegating to - * {@link PrivilegePolicy#actionAllowed(Role, Privilege, Restrictable)} - * - * @see ch.eitchnet.privilege.handler.PrivilegeHandler#actionAllowed(ch.eitchnet.privilege.model.RoleRep, - * ch.eitchnet.privilege.model.Restrictable) - */ - @Override - public void actionAllowed(RoleRep roleRep, Restrictable restrictable) { - - // user and restrictable must not be null - if (roleRep == null) - throw new PrivilegeException("Role may not be null!"); - else if (restrictable == null) - throw new PrivilegeException("Restrictable may not be null!"); - - // get role for the roleRep - Role role = this.persistenceHandler.getRole(roleRep.getName()); - - // validate that the role exists - if (role == null) { - throw new PrivilegeException("No Role exists with the name " + roleRep.getName()); - } - - // delegate to method with Role - actionAllowed(role, restrictable); - } - - /** - * Checks if the {@link Role} has access to the {@link Restrictable} by delegating to - * {@link PrivilegePolicy#actionAllowed(Role, Privilege, Restrictable)} - * - * @param role - * the role which wants to perform the action - * @param restrictable - * the {@link Restrictable} which is to be checked for authorization - */ - private boolean actionAllowed(Role role, Restrictable restrictable) { - - // validate PrivilegeName for this restrictable - String privilegeName = restrictable.getPrivilegeName(); - if (privilegeName == null || privilegeName.length() < 3) { - throw new PrivilegeException( - "The PrivilegeName may not be shorter than 3 characters. Invalid Restrictable " - + restrictable.getClass().getName()); - } - - // If the role does not have this privilege, then stop as another role might have this privilege - if (!role.hasPrivilege(privilegeName)) { - return false; - } - - // get the privilege for this restrictable - Privilege privilege = role.getPrivilegeMap().get(privilegeName); - - // check if all is allowed - if (privilege.isAllAllowed()) { - return true; - } - - // otherwise delegate checking to the policy configured for this privilege - PrivilegePolicy policy = getPolicy(privilege.getPolicy()); - if (policy == null) { - throw new PrivilegeException("PrivilegePolicy " + privilege.getPolicy() + " does not exist for Privilege " - + privilegeName); - } - - // delegate checking to privilege policy - policy.actionAllowed(role, privilege, restrictable); - - // the policy must throw an exception if action not allowed, - // so return true if we arrive here - return true; - } - @Override public void isCertificateValid(Certificate certificate) { @@ -856,24 +746,17 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { throw new PrivilegeException("Certificate may not be null!"); // first see if a session exists for this certificate - CertificateSessionPair certificateSessionPair = this.sessionMap.get(certificate.getSessionId()); - if (certificateSessionPair == null) + PrivilegeContext privilegeContext = this.privilegeContextMap.get(certificate.getSessionId()); + if (privilegeContext == null) throw new AccessDeniedException("There is no session information for " + certificate.toString()); // validate certificate has not been tampered with - Certificate sessionCertificate = certificateSessionPair.certificate; + Certificate sessionCertificate = privilegeContext.getCertificate(); if (!sessionCertificate.equals(certificate)) throw new PrivilegeException("Received illegal certificate for session id " + certificate.getSessionId()); - // TODO is validating authToken overkill since the two certificates have already been checked on equality? - // validate authToken from certificate using the sessions authPassword - String authToken = certificate.getAuthToken(certificateSessionPair.session.getAuthPassword()); - if (authToken == null || !authToken.equals(certificateSessionPair.session.getAuthToken())) - throw new PrivilegeException("Received illegal certificate data for session id " - + certificate.getSessionId()); - // get user object - User user = this.persistenceHandler.getUser(certificateSessionPair.session.getUsername()); + User user = this.persistenceHandler.getUser(privilegeContext.getUsername()); // if user exists, then certificate is valid if (user == null) { @@ -884,6 +767,15 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { // everything is ok } + @Override + public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException { + + // first validate certificate + isCertificateValid(certificate); + + return this.privilegeContextMap.get(certificate.getSessionId()); + } + @Override public void validateIsPrivilegeAdmin(Certificate certificate) throws PrivilegeException { @@ -975,8 +867,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { } this.lastSessionId = 0l; - this.sessionMap = Collections.synchronizedMap(new HashMap()); - this.systemUserCertificateMap = Collections.synchronizedMap(new HashMap()); + this.privilegeContextMap = Collections.synchronizedMap(new HashMap()); this.initialized = true; } @@ -987,7 +878,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { * the role for which the policies are to be checked */ private void validatePolicies(Role role) { - for (Privilege privilege : role.getPrivilegeMap().values()) { + for (String privilegeName : role.getPrivilegeNames()) { + IPrivilege privilege = role.getPrivilege(privilegeName); String policy = privilege.getPolicy(); if (policy != null && !this.policyMap.containsKey(policy)) { throw new PrivilegeException("Policy " + policy + " for Privilege " + privilege.getName() @@ -1003,37 +895,6 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { return Long.toString(++this.lastSessionId % Long.MAX_VALUE); } - /** - * An internal class used to keep a record of sessions with the certificate - * - * @author Robert von Burg - */ - protected class CertificateSessionPair { - - /** - * The {@link Session} - */ - public final Session session; - - /** - * The {@link Certificate} - */ - public final Certificate certificate; - - /** - * Creates a new {@link CertificateSessionPair} with the given session and certificate - * - * @param session - * the session - * @param certificate - * the certificate - */ - public CertificateSessionPair(Session session, Certificate certificate) { - this.session = session; - this.certificate = certificate; - } - } - /** * Passwords should not be kept as strings, as string are immutable, this method thus clears the byte array so that * the password is not in memory anymore @@ -1071,10 +932,10 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { checkPrivilege(actionClassname, systemUser); // get certificate for this system user - Certificate systemUserCertificate = getSystemUserCertificate(systemUsername); + PrivilegeContext systemUserPrivilegeContext = getSystemUserPrivilegeContext(systemUsername); // perform the action - action.execute(systemUserCertificate); + action.execute(systemUserPrivilegeContext); } /** @@ -1113,14 +974,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { * * @return the {@link Certificate} for this system user */ - private Certificate getSystemUserCertificate(String systemUsername) { - - // see if a certificate has already been created for this system user - Certificate systemUserCertificate = this.systemUserCertificateMap.get(systemUsername); - if (systemUserCertificate != null) - return systemUserCertificate; - - // otherwise log this system user in, by performing a slightly different authentication + private PrivilegeContext getSystemUserPrivilegeContext(String systemUsername) { // we only work with hashed passwords String passwordHash = this.encryptionHandler.convertToHash(systemUsername.getBytes()); @@ -1156,17 +1010,51 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { String sessionId = nextSessionId(); // create a new certificate, with details of the user - systemUserCertificate = new Certificate(sessionId, systemUsername, authToken, authPassword, user.getLocale(), - new HashMap(user.getProperties())); + Certificate systemUserCertificate = new Certificate(sessionId, System.currentTimeMillis(), systemUsername, + authToken, authPassword, user.getLocale(), new HashMap(user.getProperties())); - // create and save a new session - Session session = new Session(sessionId, systemUsername, authToken, authPassword, System.currentTimeMillis()); - this.sessionMap.put(sessionId, new CertificateSessionPair(session, systemUserCertificate)); + // create and save a new privilege context + PrivilegeContext privilegeContext = buildPrivilegeContext(systemUserCertificate, user); // log DefaultPrivilegeHandler.logger.info("The system user " + systemUsername + " is logged in with session " - + session); + + systemUserCertificate); - return systemUserCertificate; + return privilegeContext; + } + + /** + *

+ * This method instantiates a {@link PrivilegePolicy} object from the given policyName. The {@link PrivilegePolicy} + * is not stored in a database. The privilege name is a class name and is then used to instantiate a new + * {@link PrivilegePolicy} object + *

+ * + * @param policyName + * the class name of the {@link PrivilegePolicy} object to return + * + * @return the {@link PrivilegePolicy} object + * + * @throws PrivilegeException + * if the {@link PrivilegePolicy} object for the given policy name could not be instantiated + */ + private PrivilegePolicy getPolicy(String policyName) { + + // get the policies class + Class policyClazz = this.policyMap.get(policyName); + if (policyClazz == null) { + return null; + } + + // instantiate the policy + PrivilegePolicy policy; + try { + policy = ClassHelper.instantiateClass(policyClazz); + } catch (Exception e) { + throw new PrivilegeException("The class for the policy with the name " + policyName + " does not exist!" + + policyName, e); + } + + return policy; } } diff --git a/src/main/java/ch/eitchnet/privilege/handler/PersistenceHandler.java b/src/main/java/ch/eitchnet/privilege/handler/PersistenceHandler.java index 557d1fc48..a7dcc8b43 100644 --- a/src/main/java/ch/eitchnet/privilege/handler/PersistenceHandler.java +++ b/src/main/java/ch/eitchnet/privilege/handler/PersistenceHandler.java @@ -22,8 +22,8 @@ package ch.eitchnet.privilege.handler; import java.util.List; import java.util.Map; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.Restrictable; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; import ch.eitchnet.privilege.policy.PrivilegePolicy; @@ -37,7 +37,7 @@ import ch.eitchnet.privilege.policy.PrivilegePolicy; *

* The {@link PersistenceHandler} also serves the special {@link PrivilegePolicy} objects. These policies are special * objects which implement an algorithm to define if an action is allowed on a {@link Restrictable} by a {@link Role} - * and {@link Privilege} + * and {@link IPrivilege} *

* * @author Robert von Burg diff --git a/src/main/java/ch/eitchnet/privilege/handler/PrivilegeHandler.java b/src/main/java/ch/eitchnet/privilege/handler/PrivilegeHandler.java index 7889905e7..ec0d5376a 100644 --- a/src/main/java/ch/eitchnet/privilege/handler/PrivilegeHandler.java +++ b/src/main/java/ch/eitchnet/privilege/handler/PrivilegeHandler.java @@ -25,14 +25,13 @@ import java.util.Locale; import ch.eitchnet.privilege.base.AccessDeniedException; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.IPrivilege; +import ch.eitchnet.privilege.model.PrivilegeContext; import ch.eitchnet.privilege.model.PrivilegeRep; -import ch.eitchnet.privilege.model.Restrictable; import ch.eitchnet.privilege.model.RoleRep; import ch.eitchnet.privilege.model.UserRep; import ch.eitchnet.privilege.model.UserState; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.Role; -import ch.eitchnet.privilege.model.internal.Session; import ch.eitchnet.privilege.model.internal.User; /** @@ -222,7 +221,7 @@ public interface PrivilegeHandler { * @param roleName * the roleName of the {@link Role} to which the privilege should be added * @param privilegeRep - * the representation of the {@link Privilege} which should be added to the {@link Role} + * the representation of the {@link IPrivilege} which should be added to the {@link Role} * * @throws AccessDeniedException * if the user for this certificate may not perform the action @@ -335,49 +334,15 @@ public interface PrivilegeHandler { public Certificate authenticate(String username, byte[] password) throws AccessDeniedException; /** - * Invalidates the {@link Session} for the given {@link Certificate}, effectively logging out the user who was - * authenticated with the credentials associated to the given {@link Certificate} + * Invalidates the session for the given {@link Certificate}, effectively logging out the user who was authenticated + * with the credentials associated to the given {@link Certificate} * * @param certificate - * the {@link Certificate} for which the {@link Session} is to be invalidated - * @return true if the {@link Session} was still valid and is now invalidated, false otherwise + * the {@link Certificate} for which the session is to be invalidated + * @return true if the session was still valid and is now invalidated, false otherwise */ public boolean invalidateSession(Certificate certificate); - /** - * Checks if the {@link User} registered to the given {@link Certificate} is allowed to access the - * {@link Restrictable} - * - * @param certificate - * the {@link Certificate} of the user which has the privilege to perform this action - * @param restrictable - * the {@link Restrictable} to which the user wants access - * - * @throws AccessDeniedException - * if the user for this certificate may not perform the action defined by the {@link Restrictable} - * implementation - * @throws PrivilegeException - * if there is anything wrong with this certificate - */ - public void actionAllowed(Certificate certificate, Restrictable restrictable) throws AccessDeniedException, - PrivilegeException; - - /** - * Checks if the {@link RoleRep} is allowed to access the {@link Restrictable} - * - * @param roleRep - * the {@link RoleRep} for which access to the {@link Restrictable} is to be checked - * @param restrictable - * the {@link Restrictable} to which access is to be checked - * - * @throws PrivilegeException - * if the {@link Role} does not exist - * @throws AccessDeniedException - * if the role may not perform the action defined by the {@link Restrictable} implementation - */ - public void actionAllowed(RoleRep roleRep, Restrictable restrictable) throws PrivilegeException, - AccessDeniedException; - /** * Checks if the given {@link Certificate} is valid. This means that the certificate is for a valid session and that * the user exists for the certificate. This method checks if the {@link Certificate} has been tampered with @@ -390,6 +355,20 @@ public interface PrivilegeHandler { */ public void isCertificateValid(Certificate certificate) throws PrivilegeException; + /** + * Returns the {@link PrivilegeContext} for the given {@link Certificate}. The {@link PrivilegeContext} is an + * encapsulated state of a user's privileges so that for the duration of a user's call, the user can perform their + * actions and do not need to access the {@link PrivilegeHandler} anymore + * + * @param certificate + * a valid {@link Certificate} for which a {@link PrivilegeContext} is to be returned + * @return the {@link PrivilegeContext} for the given {@link Certificate} + * + * @throws PrivilegeException + * if there is a configuration error or the {@link Certificate} is invalid + */ + public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException; + /** *

* Validates if this {@link Certificate} is for a {@link ch.eitchnet.privilege.model.internal.User} with diff --git a/src/main/java/ch/eitchnet/privilege/handler/SystemUserAction.java b/src/main/java/ch/eitchnet/privilege/handler/SystemUserAction.java index d59aba87b..724d8a32d 100644 --- a/src/main/java/ch/eitchnet/privilege/handler/SystemUserAction.java +++ b/src/main/java/ch/eitchnet/privilege/handler/SystemUserAction.java @@ -20,6 +20,7 @@ package ch.eitchnet.privilege.handler; import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.PrivilegeContext; /** * With this interface system actions, which are to be performed in an automated fashion, i.e. by cron jobs, can be @@ -34,8 +35,11 @@ public interface SystemUserAction { * This method will be called by the {@link PrivilegeHandler} when an authorized {@link Certificate} has been * generated to allow this action to properly validate its execution * - * @param certificate - * the {@link Certificate} which was generated for a valid system user + * TODO: I'm not really happy with this... we might want to pass the certificate and then force the action to + * validate it to get the {@link PrivilegeContext} - we don't want the {@link PrivilegeContext} to live forever... + * + * @param privilegeContext + * the {@link PrivilegeContext} which was generated for a valid system user */ - public void execute(Certificate certificate); + public void execute(PrivilegeContext privilegeContext); } diff --git a/src/main/java/ch/eitchnet/privilege/helper/CertificateThreadLocal.java b/src/main/java/ch/eitchnet/privilege/helper/CertificateThreadLocal.java deleted file mode 100644 index fe75d24c0..000000000 --- a/src/main/java/ch/eitchnet/privilege/helper/CertificateThreadLocal.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2012 - * - * This file is part of ??????????????? - * - * ?????????????? is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Privilege is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with ????????????????. If not, see . - * - */ -package ch.eitchnet.privilege.helper; - -import ch.eitchnet.privilege.model.Certificate; - -/** - * This {@link ThreadLocal} holds a reference to the {@link Certificate} which allows any code segment to perform - * further authorization before executing - * - * @author Robert von Burg - */ -public class CertificateThreadLocal extends ThreadLocal { - - private static final CertificateThreadLocal instance; - static { - instance = new CertificateThreadLocal(); - } - - public static CertificateThreadLocal getInstance() { - return CertificateThreadLocal.instance; - } - - public static Certificate getCertificate() { - return CertificateThreadLocal.instance.get(); - } - - public static void setCertificate(Certificate certificate) { - CertificateThreadLocal.instance.set(certificate); - } -} diff --git a/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.java b/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.java new file mode 100644 index 000000000..c84da0b69 --- /dev/null +++ b/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, Robert von Burg + * + * All rights reserved. + * + * This file is part of the XXX. + * + * XXX is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * XXX is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XXX. If not, see + * . + */ +package ch.eitchnet.privilege.i18n; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * @author Robert von Burg + * + */ +public class PrivilegeMessages { + private static final String BUNDLE_NAME = "ch.eitchnet.privilege.i18n.PrivilegeMessages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); + + private PrivilegeMessages() { + } + + public static String getString(String key) { + try { + return RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } +} diff --git a/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.properties b/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.properties new file mode 100644 index 000000000..62f19745c --- /dev/null +++ b/src/main/java/ch/eitchnet/privilege/i18n/PrivilegeMessages.properties @@ -0,0 +1,6 @@ +Privilege.accessdenied.noprivilege=User {0} does not have Privilege {1} needed for Restrictable {2} +Privilege.illegalArgument.nonstring=\ {1} has returned a non-string privilege value\! +Privilege.illegalArgument.privilegeNameMismatch=The passed privilege has the name {0} but the restrictable is referencing privilege {1} +Privilege.privilegeNameEmpty=The PrivilegeName for the Restrictable is null or empty: {0} +Privilege.privilegeNull=Privilege may not be null\! +Privilege.restrictableNull=Restrictable may not be null\! diff --git a/src/main/java/ch/eitchnet/privilege/model/Certificate.java b/src/main/java/ch/eitchnet/privilege/model/Certificate.java index ca7710313..5b6bebfe0 100644 --- a/src/main/java/ch/eitchnet/privilege/model/Certificate.java +++ b/src/main/java/ch/eitchnet/privilege/model/Certificate.java @@ -25,7 +25,7 @@ import java.util.Map; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.internal.Session; +import ch.eitchnet.utils.helper.StringHelper; /** * The {@link Certificate} is the object a client keeps when accessing a Privilege enabled system. This object is the @@ -39,6 +39,7 @@ public final class Certificate implements Serializable { private static final long serialVersionUID = 1L; private final String sessionId; + private final long loginTime; private final String username; private final String authToken; private final String authPassword; @@ -72,15 +73,25 @@ public final class Certificate implements Serializable { * a {@link Map} containing string value pairs of properties for the logged in user. These properties can * be edited and can be used for the user to change settings of this session */ - public Certificate(String sessionId, String username, String authToken, String authPassword, Locale locale, - Map propertyMap) { + public Certificate(String sessionId, long loginTime, String username, String authToken, String authPassword, + Locale locale, Map propertyMap) { // validate arguments are not null - if (sessionId == null || username == null || authToken == null || authPassword == null) { - throw new PrivilegeException("One of the arguments is null!"); + if (StringHelper.isEmpty(sessionId)) { + throw new PrivilegeException("sessionId is null!"); + } + if (StringHelper.isEmpty(username)) { + throw new PrivilegeException("username is null!"); + } + if (StringHelper.isEmpty(authToken)) { + throw new PrivilegeException("authToken is null!"); + } + if (StringHelper.isEmpty(authPassword)) { + throw new PrivilegeException("authPassword is null!"); } this.sessionId = sessionId; + this.loginTime = loginTime; this.username = username; this.authToken = authToken; this.authPassword = authPassword; @@ -130,6 +141,13 @@ public final class Certificate implements Serializable { return this.username; } + /** + * @return the loginTime + */ + public long getLoginTime() { + return this.loginTime; + } + /** * Returns the authToken if the given authPassword is correct, null otherwise * diff --git a/src/main/java/ch/eitchnet/privilege/model/IPrivilege.java b/src/main/java/ch/eitchnet/privilege/model/IPrivilege.java new file mode 100644 index 000000000..f9ddbe93f --- /dev/null +++ b/src/main/java/ch/eitchnet/privilege/model/IPrivilege.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, Robert von Burg + * + * All rights reserved. + * + * This file is part of the XXX. + * + * XXX is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * XXX is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XXX. If not, see + * . + */ +package ch.eitchnet.privilege.model; + +import java.util.Set; + +import ch.eitchnet.privilege.model.internal.Role; +import ch.eitchnet.privilege.policy.PrivilegePolicy; + +/** + *

+ * {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it + * which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a + * {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow + * lists configured which is used to evaluate if privilege is granted to a {@link Restrictable} + *

+ * + * @author Robert von Burg + * + */ +public interface IPrivilege { + + /** + * @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients + */ + public abstract PrivilegeRep asPrivilegeRep(); + + /** + * @return the name + */ + public abstract String getName(); + + /** + * @return the policy + */ + public abstract String getPolicy(); + + /** + * @return the allAllowed + */ + public abstract boolean isAllAllowed(); + + /** + * @return the allowList + */ + public abstract Set getAllowList(); + + /** + * @return the denyList + */ + public abstract Set getDenyList(); + + /** + * @return true if there are values in the allow list + */ + public abstract boolean hasAllowed(); + + /** + * @return if the value is in the allow list + */ + public abstract boolean isAllowed(String value); + + /** + * @return true if there are values in the deny list + */ + public abstract boolean hasDenied(); + + /** + * @return true if the value is in the deny list + */ + public abstract boolean isDenied(String value); + +} \ No newline at end of file diff --git a/src/main/java/ch/eitchnet/privilege/model/PrivilegeContext.java b/src/main/java/ch/eitchnet/privilege/model/PrivilegeContext.java new file mode 100644 index 000000000..661434a18 --- /dev/null +++ b/src/main/java/ch/eitchnet/privilege/model/PrivilegeContext.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012, Robert von Burg + * + * All rights reserved. + * + * This file is part of the XXX. + * + * XXX is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * XXX is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XXX. If not, see + * . + */ +package ch.eitchnet.privilege.model; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import ch.eitchnet.privilege.base.AccessDeniedException; +import ch.eitchnet.privilege.base.PrivilegeException; +import ch.eitchnet.privilege.i18n.PrivilegeMessages; +import ch.eitchnet.privilege.policy.PrivilegePolicy; + +/** + * This context gives access to a logged in user's privilege data e.g. the {@link UserRep}, {@link Certificate} and the + * user's list of {@link PrivilegeRep} + * + *

+ * Note: This is an internal object which is not to be serialized to clients + *

+ * + * @author Robert von Burg + */ +public class PrivilegeContext { + + // + // object state + // + + private UserRep userRep; + private Certificate certificate; + private Map privileges; + private Map policies; + + public PrivilegeContext(UserRep userRep, Certificate certificate, Map privileges, + Map policies) { + this.userRep = userRep; + this.certificate = certificate; + this.privileges = Collections.unmodifiableMap(new HashMap(privileges)); + this.policies = Collections.unmodifiableMap(new HashMap(policies)); + } + + public UserRep getUserRep() { + return this.userRep; + } + + public Certificate getCertificate() { + return this.certificate; + } + + public String getUsername() { + return this.userRep.getUsername(); + } + + public Set getPrivilegeNames() { + return this.privileges.keySet(); + } + + // + // business logic + // + + /** + * Validates if the user for this context has the privilege to access to the given {@link Restrictable}. If the user + * has the privilege, then this method returns with no exception and void, if the user does not have the privilege, + * then a {@link AccessDeniedException} is thrown. + * + * @param restrictable + * the {@link Restrictable} which the user wants to access + * + * @throws AccessDeniedException + * if the user does not have access + * @throws PrivilegeException + * if there is an internal error due to wrongly configured privileges or programming errors + */ + public void validateAction(Restrictable restrictable) throws AccessDeniedException, PrivilegeException { + + // the the privilege for the restrictable + String privilegeName = restrictable.getPrivilegeName(); + IPrivilege privilege = this.privileges.get(privilegeName); + if (privilege == null) { + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), + getUsername(), privilegeName, restrictable.getClass().getName()); + throw new AccessDeniedException(msg); + } + + // get the policy referenced by the restrictable + String policyName = privilege.getPolicy(); + PrivilegePolicy policy = this.policies.get(policyName); + if (policy == null) { + String msg = "The PrivilegePolicy {0} does not exist on the PrivilegeContext!"; + throw new PrivilegeException(MessageFormat.format(msg, policyName)); + } + + // delegate to the policy + policy.validateAction(privilege, restrictable); + } + + // + // ThreadLocal binding + // + + private static final ThreadLocal threadLocal = new ThreadLocal(); + + /** + * Returns the currently {@link ThreadLocal} bound {@link PrivilegeContext} or throws a {@link PrivilegeException} + * if none is set + * + * @return the currently {@link ThreadLocal} bound {@link PrivilegeContext} or throws a {@link PrivilegeException} + * if none is set + * + * @throws PrivilegeException + * if no {@link PrivilegeContext} is set + */ + public static PrivilegeContext get() throws PrivilegeException { + PrivilegeContext privilegeContext = PrivilegeContext.threadLocal.get(); + if (privilegeContext == null) { + throw new PrivilegeException("There is no PrivilegeContext currently bound to the ThreadLocal!"); + } + return privilegeContext; + } + + /** + * Bind a {@link PrivilegeContext} to the {@link ThreadLocal} or throws a {@link PrivilegeException} if one is + * already bound + * + * @param privilegeContext + * the {@link PrivilegeContext} to bind + * + * @throws PrivilegeException + * if e {@link PrivilegeContext} is already bound + */ + public static void set(PrivilegeContext privilegeContext) throws PrivilegeException { + PrivilegeContext currentContext = PrivilegeContext.threadLocal.get(); + if (privilegeContext != null && currentContext != null) { + throw new PrivilegeException("There already is a PrivilegeContext bound to the ThreadLocal!"); + } + PrivilegeContext.threadLocal.set(privilegeContext); + } +} diff --git a/src/main/java/ch/eitchnet/privilege/model/PrivilegeRep.java b/src/main/java/ch/eitchnet/privilege/model/PrivilegeRep.java index c74725a80..b2a316c5b 100644 --- a/src/main/java/ch/eitchnet/privilege/model/PrivilegeRep.java +++ b/src/main/java/ch/eitchnet/privilege/model/PrivilegeRep.java @@ -24,14 +24,14 @@ import java.util.Set; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.policy.PrivilegePolicy; +import ch.eitchnet.utils.helper.StringHelper; /** - * To keep certain details of the {@link Privilege} itself hidden from remote clients and make sure instances are only + * To keep certain details of the {@link IPrivilege} itself hidden from remote clients and make sure instances are only * edited by users with the correct privilege, this representational version is allowed to be viewed by remote clients - * and simply wraps all public data from the {@link Privilege} + * and simply wraps all public data from the {@link IPrivilege} * * @author Robert von Burg */ @@ -53,12 +53,12 @@ public class PrivilegeRep implements Serializable { * @param policy * the {@link PrivilegePolicy} configured to evaluate if the privilege is granted * @param allAllowed - * a boolean defining if a {@link Role} with this {@link Privilege} has unrestricted access to a + * a boolean defining if a {@link Role} with this {@link IPrivilege} has unrestricted access to a * {@link Restrictable} * @param denyList - * a list of deny rules for this {@link Privilege} + * a list of deny rules for this {@link IPrivilege} * @param allowList - * a list of allow rules for this {@link Privilege} + * a list of allow rules for this {@link IPrivilege} */ public PrivilegeRep(String name, String policy, boolean allAllowed, Set denyList, Set allowList) { this.name = name; @@ -66,6 +66,29 @@ public class PrivilegeRep implements Serializable { this.allAllowed = allAllowed; this.denyList = denyList; this.allowList = allowList; + + validate(); + } + + /** + * Validates that all required fields are set + */ + public void validate() { + + if (StringHelper.isEmpty(this.name)) { + throw new PrivilegeException("No name defined!"); + } + + if (StringHelper.isEmpty(this.policy)) { + throw new PrivilegeException("policy is null!"); + } + + if (this.denyList == null) { + throw new PrivilegeException("denyList is null"); + } + if (this.allowList == null) { + throw new PrivilegeException("allowList is null"); + } } /** @@ -143,48 +166,6 @@ public class PrivilegeRep implements Serializable { this.allowList = allowList; } - /** - *

- * Validates this {@link PrivilegeRep} so that a {@link Privilege} object can later be created from it - *

- * - * TODO write comment on how validation is done - */ - public void validate() { - - if (this.name == null || this.name.isEmpty()) { - throw new PrivilegeException("No name defined!"); - } - - // if not all allowed, then validate that deny and allow lists are defined - if (this.allAllowed) { - - // all allowed means no policy will be used - if (this.policy != null && !this.policy.isEmpty()) { - throw new PrivilegeException("All is allowed, so Policy may not be set!"); - } - - if (this.denyList != null && !this.denyList.isEmpty()) - throw new PrivilegeException("All is allowed, so deny list must be null"); - if (this.allowList != null && !this.allowList.isEmpty()) - throw new PrivilegeException("All is allowed, so allow list must be null"); - - } else { - - // not all allowed, so policy must be set - if (this.policy == null || this.policy.isEmpty()) { - throw new PrivilegeException("All is not allowed, so Policy must be defined!"); - } - - if (this.denyList == null) { - throw new PrivilegeException("All is not allowed, so deny list must be set, even if empty"); - } - if (this.allowList == null) { - throw new PrivilegeException("All is not allowed, so allow list must be set, even if empty"); - } - } - } - /** * Returns a string representation of this object displaying its concrete type and its values * diff --git a/src/main/java/ch/eitchnet/privilege/model/Restrictable.java b/src/main/java/ch/eitchnet/privilege/model/Restrictable.java index 95ef2e3c4..99795bb9e 100644 --- a/src/main/java/ch/eitchnet/privilege/model/Restrictable.java +++ b/src/main/java/ch/eitchnet/privilege/model/Restrictable.java @@ -19,14 +19,13 @@ */ package ch.eitchnet.privilege.model; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.policy.PrivilegePolicy; /** *

* Objects implementing this interface are used to grant/restrict privileges to them. A {@link PrivilegePolicy} * implements the logic on granting/restricting privileges for a {@link Restrictable} and the - * {@link #getPrivilegeName()} is used to find the {@link Privilege} which has the associated {@link PrivilegePolicy} + * {@link #getPrivilegeName()} is used to find the {@link IPrivilege} which has the associated {@link PrivilegePolicy} * for evaluating access *

* @@ -36,9 +35,9 @@ import ch.eitchnet.privilege.policy.PrivilegePolicy; public interface Restrictable { /** - * Returns the name of the {@link Privilege} which is to be used to validate privileges against + * Returns the name of the {@link IPrivilege} which is to be used to validate privileges against * - * @return the name of the {@link Privilege} which is to be used to validate privileges against + * @return the name of the {@link IPrivilege} which is to be used to validate privileges against */ public String getPrivilegeName(); diff --git a/src/main/java/ch/eitchnet/privilege/model/RoleRep.java b/src/main/java/ch/eitchnet/privilege/model/RoleRep.java index 06fd4a9bb..dfee0572c 100644 --- a/src/main/java/ch/eitchnet/privilege/model/RoleRep.java +++ b/src/main/java/ch/eitchnet/privilege/model/RoleRep.java @@ -22,7 +22,9 @@ package ch.eitchnet.privilege.model; import java.io.Serializable; import java.util.Map; +import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.model.internal.Role; +import ch.eitchnet.utils.helper.StringHelper; /** * To keep certain details of the {@link Role} itself hidden from remote clients and make sure instances are only edited @@ -47,8 +49,19 @@ public class RoleRep implements Serializable { * the map of privileges granted to this role */ public RoleRep(String name, Map privilegeMap) { + this.name = name; this.privilegeMap = privilegeMap; + + validate(); + } + + /** + * validates that all required fields are set + */ + public void validate() { + if (StringHelper.isEmpty(this.name)) + throw new PrivilegeException("name is null"); } /** diff --git a/src/main/java/ch/eitchnet/privilege/model/UserRep.java b/src/main/java/ch/eitchnet/privilege/model/UserRep.java index 01f0f786a..118cb727c 100644 --- a/src/main/java/ch/eitchnet/privilege/model/UserRep.java +++ b/src/main/java/ch/eitchnet/privilege/model/UserRep.java @@ -24,8 +24,10 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; +import ch.eitchnet.utils.helper.StringHelper; /** * To keep certain details of the {@link User} itself hidden from remote clients and make sure instances are only edited @@ -77,6 +79,32 @@ public class UserRep implements Serializable { this.roles = roles; this.locale = locale; this.propertyMap = propertyMap; + + validate(); + } + + /** + * Validates that all required fields are set + */ + public void validate() { + + if (StringHelper.isEmpty(this.userId)) + throw new PrivilegeException("userId is null or empty"); + + if (StringHelper.isEmpty(this.username)) + throw new PrivilegeException("username is null or empty"); + + if (StringHelper.isEmpty(this.firstname)) + throw new PrivilegeException("firstname is null or empty"); + + if (StringHelper.isEmpty(this.surname)) + throw new PrivilegeException("surname is null or empty"); + + if (this.userState == null) + throw new PrivilegeException("userState is null"); + + if (this.roles == null) + throw new PrivilegeException("roles is null"); } /** diff --git a/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeContainerModel.java b/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeContainerModel.java index 1b1d118cf..a30db711c 100644 --- a/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeContainerModel.java +++ b/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeContainerModel.java @@ -32,6 +32,10 @@ import ch.eitchnet.privilege.policy.PrivilegePolicy; * This class is used during XML parsing to hold the model before it is properly validated and made accessible through * the {@link PrivilegeHandler} * + *

+ * Note: This is an internal object which is not to be serialized or passed to clients + *

+ * * @author Robert von Burg */ public class PrivilegeContainerModel { diff --git a/src/main/java/ch/eitchnet/privilege/model/internal/Privilege.java b/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeImpl.java similarity index 63% rename from src/main/java/ch/eitchnet/privilege/model/internal/Privilege.java rename to src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeImpl.java index 2bb456c0b..c32623f41 100644 --- a/src/main/java/ch/eitchnet/privilege/model/internal/Privilege.java +++ b/src/main/java/ch/eitchnet/privilege/model/internal/PrivilegeImpl.java @@ -25,20 +25,22 @@ import java.util.Set; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.handler.PrivilegeHandler; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.PrivilegeRep; import ch.eitchnet.privilege.model.Restrictable; import ch.eitchnet.privilege.policy.PrivilegePolicy; +import ch.eitchnet.utils.helper.StringHelper; /** *

- * {@link Privilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it which - * defines the privileges a logged in user with that role has. If the {@link Privilege} has a {@link PrivilegePolicy} - * defined, then that policy will be used for finer granularity and with the deny and allow lists configured which is - * used to evaluate if privilege is granted to a {@link Restrictable} + * {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it + * which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a + * {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow + * lists configured which is used to evaluate if privilege is granted to a {@link Restrictable} *

* *

- * {@link Privilege}s have allow and deny rules which the configured {@link PrivilegeHandler} uses to + * {@link IPrivilege}s have allow and deny rules which the configured {@link PrivilegeHandler} uses to *

* *

@@ -48,7 +50,7 @@ import ch.eitchnet.privilege.policy.PrivilegePolicy; * * @author Robert von Burg */ -public final class Privilege { +public final class PrivilegeImpl implements IPrivilege { private final String name; private final String policy; @@ -65,66 +67,59 @@ public final class Privilege { * the {@link PrivilegePolicy} configured to evaluate if the privilege is granted. If null, then * privilege is granted * @param allAllowed - * a boolean defining if a {@link Role} with this {@link Privilege} has unrestricted access to a + * a boolean defining if a {@link Role} with this {@link PrivilegeImpl} has unrestricted access to a * {@link Restrictable} in which case the deny and allow lists are ignored and can be null * @param denyList - * a list of deny rules for this {@link Privilege}, can be null if all allowed + * a list of deny rules for this {@link PrivilegeImpl}, can be null if all allowed * @param allowList - * a list of allow rules for this {@link Privilege}, can be null if all allowed + * a list of allow rules for this {@link PrivilegeImpl}, can be null if all allowed */ - public Privilege(String name, String policy, boolean allAllowed, Set denyList, Set allowList) { + public PrivilegeImpl(String name, String policy, boolean allAllowed, Set denyList, Set allowList) { - if (name == null || name.isEmpty()) { + if (StringHelper.isEmpty(name)) { throw new PrivilegeException("No name defined!"); } - this.name = name; - - // if not all allowed, then validate that deny and allow lists are defined - if (allAllowed) { - - this.allAllowed = true; - - // all allowed means no policy will be used - this.policy = null; - - this.denyList = Collections.emptySet(); - this.allowList = Collections.emptySet(); - } else { - - this.allAllowed = false; - - // not all allowed, so policy must be set - if (policy == null || policy.isEmpty()) { - throw new PrivilegeException("All is not allowed and no Policy defined!"); - } - this.policy = policy; - - if (denyList == null) { - throw new PrivilegeException("All is not allowed and no denyList defined!"); - } - this.denyList = Collections.unmodifiableSet(denyList); - - if (allowList == null) { - throw new PrivilegeException("All is not allowed and no allowList defined!"); - } - this.allowList = Collections.unmodifiableSet(allowList); + if (StringHelper.isEmpty(policy)) { + throw new PrivilegeException("Policy may not be empty!"); } + if (denyList == null) { + throw new PrivilegeException("denyList is null!"); + } + if (allowList == null) { + throw new PrivilegeException("allowList is null!"); + } + + this.name = name; + this.allAllowed = allAllowed; + this.policy = policy; + this.denyList = Collections.unmodifiableSet(denyList); + this.allowList = Collections.unmodifiableSet(allowList); } /** - * Constructs a {@link Privilege} from the {@link PrivilegeRep} + * Constructs a {@link PrivilegeImpl} from the {@link PrivilegeRep} * * @param privilegeRep - * the {@link PrivilegeRep} from which to create the {@link Privilege} + * the {@link PrivilegeRep} from which to create the {@link PrivilegeImpl} */ - public Privilege(PrivilegeRep privilegeRep) { + public PrivilegeImpl(PrivilegeRep privilegeRep) { this(privilegeRep.getName(), privilegeRep.getPolicy(), privilegeRep.isAllAllowed(), privilegeRep.getDenyList(), privilegeRep.getDenyList()); } + /** + * @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients + */ + @Override + public PrivilegeRep asPrivilegeRep() { + return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet(this.denyList), + new HashSet(this.allowList)); + } + /** * @return the name */ + @Override public String getName() { return this.name; } @@ -132,6 +127,7 @@ public final class Privilege { /** * @return the policy */ + @Override public String getPolicy() { return this.policy; } @@ -139,6 +135,7 @@ public final class Privilege { /** * @return the allAllowed */ + @Override public boolean isAllAllowed() { return this.allAllowed; } @@ -146,6 +143,7 @@ public final class Privilege { /** * @return the allowList */ + @Override public Set getAllowList() { return this.allowList; } @@ -153,16 +151,41 @@ public final class Privilege { /** * @return the denyList */ + @Override public Set getDenyList() { return this.denyList; } /** - * @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients + * @return true if there are values in the allow list */ - public PrivilegeRep asPrivilegeRep() { - return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet(this.denyList), - new HashSet(this.allowList)); + @Override + public boolean hasAllowed() { + return !this.allowList.isEmpty(); + } + + /** + * @return if the value is in the allow list + */ + @Override + public boolean isAllowed(String value) { + return this.allowList.contains(value); + } + + /** + * @return true if there are values in the deny list + */ + @Override + public boolean hasDenied() { + return !this.allowList.isEmpty(); + } + + /** + * @return true if the value is in the deny list + */ + @Override + public boolean isDenied(String value) { + return this.denyList.contains(value); } /** @@ -197,7 +220,7 @@ public final class Privilege { return false; if (getClass() != obj.getClass()) return false; - Privilege other = (Privilege) obj; + PrivilegeImpl other = (PrivilegeImpl) obj; if (this.name == null) { if (other.name != null) return false; diff --git a/src/main/java/ch/eitchnet/privilege/model/internal/Role.java b/src/main/java/ch/eitchnet/privilege/model/internal/Role.java index 70cd2b11d..9e85710de 100644 --- a/src/main/java/ch/eitchnet/privilege/model/internal/Role.java +++ b/src/main/java/ch/eitchnet/privilege/model/internal/Role.java @@ -22,10 +22,13 @@ package ch.eitchnet.privilege.model.internal; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import ch.eitchnet.privilege.base.PrivilegeException; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.PrivilegeRep; import ch.eitchnet.privilege.model.RoleRep; +import ch.eitchnet.utils.helper.StringHelper; /** *

@@ -43,7 +46,7 @@ import ch.eitchnet.privilege.model.RoleRep; public final class Role { private final String name; - private final Map privilegeMap; + private final Map privilegeMap; /** * Default constructor @@ -51,11 +54,11 @@ public final class Role { * @param name * the name of the role * @param privilegeMap - * a map of {@link Privilege}s granted to this role + * a map of {@link IPrivilege}s granted to this role */ - public Role(String name, Map privilegeMap) { + public Role(String name, Map privilegeMap) { - if (name == null || name.isEmpty()) { + if (StringHelper.isEmpty(name)) { throw new PrivilegeException("No name defined!"); } if (privilegeMap == null) { @@ -75,7 +78,7 @@ public final class Role { public Role(RoleRep roleRep) { String name = roleRep.getName(); - if (name == null || name.isEmpty()) { + if (StringHelper.isEmpty(name)) { throw new PrivilegeException("No name defined!"); } @@ -84,9 +87,9 @@ public final class Role { } // build privileges from reps - Map privilegeMap = new HashMap(roleRep.getPrivilegeMap().size()); + Map privilegeMap = new HashMap(roleRep.getPrivilegeMap().size()); for (String privilegeName : roleRep.getPrivilegeMap().keySet()) { - privilegeMap.put(privilegeName, new Privilege(roleRep.getPrivilegeMap().get(privilegeName))); + privilegeMap.put(privilegeName, new PrivilegeImpl(roleRep.getPrivilegeMap().get(privilegeName))); } this.name = name; @@ -101,21 +104,30 @@ public final class Role { } /** - * Returns the {@link Map} of {@link Privilege}s which are granted to this {@link Role} + * Returns the {@link Set} of names for the currently stored {@link IPrivilege Privileges} * - * @return the {@link Map} of {@link Privilege}s which are granted to this {@link Role} + * @return the {@link Set} of names for the currently stored {@link IPrivilege Privileges} */ - public Map getPrivilegeMap() { - return this.privilegeMap; + public Set getPrivilegeNames() { + return this.privilegeMap.keySet(); } /** - * Determines if this {@link Role} has the {@link Privilege} with the given name + * Returns the {@link IPrivilege} for the given name, null if it does not exist + * + * @return the {@link IPrivilege} for the given name, null if it does not exist + */ + public IPrivilege getPrivilege(String name) { + return this.privilegeMap.get(name); + } + + /** + * Determines if this {@link Role} has the {@link IPrivilege} with the given name * * @param name - * the name of the {@link Privilege} + * the name of the {@link IPrivilege} * - * @return true if this {@link Role} has the {@link Privilege} with the given name + * @return true if this {@link Role} has the {@link IPrivilege} with the given name */ public boolean hasPrivilege(String name) { return this.privilegeMap.containsKey(name); diff --git a/src/main/java/ch/eitchnet/privilege/model/internal/Session.java b/src/main/java/ch/eitchnet/privilege/model/internal/Session.java deleted file mode 100644 index 2ab1e45df..000000000 --- a/src/main/java/ch/eitchnet/privilege/model/internal/Session.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2010 - 2012 - * - * This file is part of Privilege. - * - * Privilege is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Privilege is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Privilege. If not, see . - * - */ -package ch.eitchnet.privilege.model.internal; - -import ch.eitchnet.privilege.base.PrivilegeException; -import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.model.Certificate; - -/** - *

- * A {@link Session} is linked to currently logged in user. The {@link PrivilegeHandler} creates an instance of this - * class once a {@link User} has successfully logged in and keeps this object private but hands out a - * {@link Certificate} which the user must use every time a privilege needs to be granted - *

- * - *

- * Note: This is an internal object which is not to be serialized or passed to clients, the client must keep his - * {@link Certificate} which is used for accessing privileges - *

- * - * @author Robert von Burg - */ -public final class Session { - - private final String sessionId; - private final String username; - private final long loginTime; - - private final String authToken; - private final String authPassword; - - /** - * Default constructor - * - *

- * Note, both the authentication token and password are private fields which are generated on login and only known - * by the {@link PrivilegeHandler} - *

- * - * @param sessionId - * the users session id - * @param username - * the users login name - * @param authToken - * the authentication token defining the users unique session and is a private field of this session. It - * corresponds with the authentication token on the {@link Certificate} - * @param authPassword - * the password to access the authentication token, this is not known to the client but set by the - * {@link PrivilegeHandler} on authentication. It corresponds with the authentication password on the - * {@link Certificate} - * @param loginTime - * the time the user logged in - */ - public Session(String sessionId, String username, String authToken, String authPassword, long loginTime) { - - if (sessionId == null || sessionId.isEmpty()) { - throw new PrivilegeException("No sessionId defined!"); - } - if (username == null || username.isEmpty()) { - throw new PrivilegeException("No username defined!"); - } - if (authToken == null || authToken.isEmpty()) { - throw new PrivilegeException("No authToken defined!"); - } - if (authPassword == null || authPassword.isEmpty()) { - throw new PrivilegeException("No authPassword defined!"); - } - - this.sessionId = sessionId; - this.username = username; - this.authToken = authToken; - this.authPassword = authPassword; - this.loginTime = loginTime; - } - - /** - * @return the sessionId - */ - public String getSessionId() { - return this.sessionId; - } - - /** - * @return the authToken - */ - public String getAuthToken() { - return this.authToken; - } - - /** - * @return the authPassword - */ - public String getAuthPassword() { - return this.authPassword; - } - - /** - * @return the username - */ - public String getUsername() { - return this.username; - } - - /** - * @return the loginTime - */ - public long getLoginTime() { - return this.loginTime; - } - - /** - * Returns a string representation of this object displaying its concrete type and its values - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Session [sessionId="); - builder.append(this.sessionId); - builder.append(", username="); - builder.append(this.username); - builder.append(", loginTime="); - builder.append(this.loginTime); - builder.append("]"); - return builder.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.authPassword == null) ? 0 : this.authPassword.hashCode()); - result = prime * result + ((this.authToken == null) ? 0 : this.authToken.hashCode()); - result = prime * result + (int) (this.loginTime ^ (this.loginTime >>> 32)); - result = prime * result + ((this.sessionId == null) ? 0 : this.sessionId.hashCode()); - result = prime * result + ((this.username == null) ? 0 : this.username.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Session other = (Session) obj; - if (this.authPassword == null) { - if (other.authPassword != null) - return false; - } else if (!this.authPassword.equals(other.authPassword)) - return false; - if (this.authToken == null) { - if (other.authToken != null) - return false; - } else if (!this.authToken.equals(other.authToken)) - return false; - if (this.loginTime != other.loginTime) - return false; - if (this.sessionId == null) { - if (other.sessionId != null) - return false; - } else if (!this.sessionId.equals(other.sessionId)) - return false; - if (this.username == null) { - if (other.username != null) - return false; - } else if (!this.username.equals(other.username)) - return false; - return true; - } -} diff --git a/src/main/java/ch/eitchnet/privilege/model/internal/User.java b/src/main/java/ch/eitchnet/privilege/model/internal/User.java index 1cd67bc2e..7e50da571 100644 --- a/src/main/java/ch/eitchnet/privilege/model/internal/User.java +++ b/src/main/java/ch/eitchnet/privilege/model/internal/User.java @@ -29,6 +29,7 @@ import java.util.Set; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.model.UserRep; import ch.eitchnet.privilege.model.UserState; +import ch.eitchnet.utils.helper.StringHelper; /** * This class defines the actual login information for a given user which can be granted privileges. Every user is @@ -84,16 +85,16 @@ public final class User { public User(String userId, String username, String password, String firstname, String surname, UserState userState, Set roles, Locale locale, Map propertyMap) { - if (userId == null || userId.isEmpty()) { + if (StringHelper.isEmpty(userId)) { throw new PrivilegeException("No UserId defined!"); } - if (username == null || username.isEmpty()) { + if (StringHelper.isEmpty(username)) { throw new PrivilegeException("No username defined!"); } - if (firstname == null || firstname.isEmpty()) { + if (StringHelper.isEmpty(firstname)) { throw new PrivilegeException("No firstname defined!"); } - if (surname == null || surname.isEmpty()) { + if (StringHelper.isEmpty(surname)) { throw new PrivilegeException("No surname defined!"); } if (userState == null) { diff --git a/src/main/java/ch/eitchnet/privilege/policy/DefaultPrivilege.java b/src/main/java/ch/eitchnet/privilege/policy/DefaultPrivilege.java index 478169cdb..3a360be94 100644 --- a/src/main/java/ch/eitchnet/privilege/policy/DefaultPrivilege.java +++ b/src/main/java/ch/eitchnet/privilege/policy/DefaultPrivilege.java @@ -19,11 +19,16 @@ */ package ch.eitchnet.privilege.policy; +import java.text.MessageFormat; + import ch.eitchnet.privilege.base.AccessDeniedException; import ch.eitchnet.privilege.base.PrivilegeException; +import ch.eitchnet.privilege.i18n.PrivilegeMessages; +import ch.eitchnet.privilege.model.IPrivilege; +import ch.eitchnet.privilege.model.PrivilegeContext; import ch.eitchnet.privilege.model.Restrictable; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.Role; +import ch.eitchnet.utils.helper.StringHelper; /** * This is a simple implementation of {@link PrivilegePolicy} which uses the {@link Restrictable#getPrivilegeName()} to @@ -36,53 +41,62 @@ public class DefaultPrivilege implements PrivilegePolicy { /** * The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege * - * @see ch.eitchnet.privilege.policy.PrivilegePolicy#actionAllowed(ch.eitchnet.privilege.model.internal.Role, - * ch.eitchnet.privilege.model.internal.Privilege, ch.eitchnet.privilege.model.Restrictable) + * @see ch.eitchnet.privilege.policy.PrivilegePolicy#validateAction(PrivilegeContext, Restrictable) */ @Override - public void actionAllowed(Role role, Privilege privilege, Restrictable restrictable) { + public void validateAction(IPrivilege privilege, Restrictable restrictable) { - // validate user is not null - if (role == null) - throw new PrivilegeException("Role may not be null!"); + if (privilege == null) + throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull")); //$NON-NLS-1$ + if (restrictable == null) + throw new PrivilegeException(PrivilegeMessages.getString("Privilege.restrictableNull")); //$NON-NLS-1$ // get the PrivilegeName String privilegeName = restrictable.getPrivilegeName(); - if (privilegeName == null || privilegeName.isEmpty()) { - throw new PrivilegeException("The PrivilegeName for the Restrictable is null or empty: " + restrictable); + if (StringHelper.isEmpty(privilegeName)) { + String msg = PrivilegeMessages.getString("Privilege.privilegeNameEmpty"); //$NON-NLS-1$ + throw new PrivilegeException(MessageFormat.format(msg, restrictable)); } + // we want the privileges names to match + if (!privilege.getName().equals(privilegeName)) { + throw new PrivilegeException(MessageFormat.format( + PrivilegeMessages.getString("Privilege.illegalArgument.privilegeNameMismatch"), //$NON-NLS-1$ + privilege.getName(), privilegeName)); + } + + // if everything is allowed, then no need to carry on + if (privilege.isAllAllowed()) + return; + // get the value on which the action is to be performed Object object = restrictable.getPrivilegeValue(); // DefaultPrivilege policy expects the privilege value to be a string if (!(object instanceof String)) { - throw new PrivilegeException(Restrictable.class.getName() + " " + restrictable.getClass().getSimpleName() - + " has returned a non-string privilege value!"); + String msg = Restrictable.class.getName() + + PrivilegeMessages.getString("Privilege.illegalArgument.nonstring"); //$NON-NLS-1$ + msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName()); + throw new PrivilegeException(msg); } String privilegeValue = (String) object; // first check values not allowed - for (String denied : privilege.getDenyList()) { - - // if value in deny list - if (denied.equals(privilegeValue)) { - - // then throw access denied - throw new AccessDeniedException("Role " + role.getName() + " does not have Privilege " + privilegeName - + " needed for Restrictable " + restrictable.getClass().getName()); - } + if (privilege.isDenied(privilegeValue)) { + // then throw access denied + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), + PrivilegeContext.get().getUsername(), privilegeName, restrictable.getClass().getName()); + throw new AccessDeniedException(msg); } // now check values allowed - for (String allowed : privilege.getAllowList()) { - if (allowed.equals(privilegeValue)) - return; - } + if (privilege.isAllowed(privilegeValue)) + return; // default is not allowed - throw new AccessDeniedException("Role " + role.getName() + " does not have Privilege " + privilegeName - + " needed for Restrictable " + restrictable.getClass().getName()); + String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), + PrivilegeContext.get().getUsername(), privilegeName, restrictable.getClass().getName()); + throw new AccessDeniedException(msg); } } diff --git a/src/main/java/ch/eitchnet/privilege/policy/PrivilegePolicy.java b/src/main/java/ch/eitchnet/privilege/policy/PrivilegePolicy.java index 62041e636..4f0372c25 100644 --- a/src/main/java/ch/eitchnet/privilege/policy/PrivilegePolicy.java +++ b/src/main/java/ch/eitchnet/privilege/policy/PrivilegePolicy.java @@ -20,20 +20,19 @@ package ch.eitchnet.privilege.policy; import ch.eitchnet.privilege.base.AccessDeniedException; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.Restrictable; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; /** *

* {@link PrivilegePolicy} implements logic to determine if a {@link User} which has the given {@link Role} and the - * given {@link Privilege} has access to the given {@link Restrictable} + * given {@link IPrivilege} has access to the given {@link Restrictable} *

* *

- * Re-think this interface and especially the {@link #actionAllowed(Role, Privilege, Restrictable)}-method... maybe we - * need one with out the {@link Privilege} in its signature? + * TODO *

* * @author Robert von Burg @@ -41,17 +40,15 @@ import ch.eitchnet.privilege.model.internal.User; public interface PrivilegePolicy { /** - * Checks if the given {@link Role} and the given {@link Privilege} has access to the given {@link Restrictable} + * Checks if the given {@link Role} and the given {@link IPrivilege} has access to the given {@link Restrictable} * - * @param role - * the {@link Role} trying to access the {@link Restrictable} * @param privilege - * the {@link Privilege} to check with + * the {@link IPrivilege} containing the permissions * @param restrictable * the {@link Restrictable} to which the user wants access * * @throws AccessDeniedException * if action not allowed */ - public void actionAllowed(Role role, Privilege privilege, Restrictable restrictable) throws AccessDeniedException; + public void validateAction(IPrivilege privilege, Restrictable restrictable) throws AccessDeniedException; } diff --git a/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelDomWriter.java b/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelDomWriter.java index 18b0e7de7..03ef69f77 100644 --- a/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelDomWriter.java +++ b/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelDomWriter.java @@ -29,7 +29,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import ch.eitchnet.privilege.helper.XmlConstants; -import ch.eitchnet.privilege.model.internal.Privilege; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; import ch.eitchnet.utils.helper.XmlHelper; @@ -124,7 +124,8 @@ public class PrivilegeModelDomWriter { roleElement.setAttribute(XmlConstants.XML_ATTR_NAME, role.getName()); - for (Privilege privilege : role.getPrivilegeMap().values()) { + for (String privilegeName : role.getPrivilegeNames()) { + IPrivilege privilege = role.getPrivilege(privilegeName); // create the privilege element Element privilegeElement = doc.createElement(XmlConstants.XML_PRIVILEGE); diff --git a/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelSaxReader.java b/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelSaxReader.java index fa85e9843..edc0490a2 100644 --- a/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelSaxReader.java +++ b/src/main/java/ch/eitchnet/privilege/xml/PrivilegeModelSaxReader.java @@ -36,8 +36,9 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.UserState; -import ch.eitchnet.privilege.model.internal.Privilege; +import ch.eitchnet.privilege.model.internal.PrivilegeImpl; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; import ch.eitchnet.utils.helper.StringHelper; @@ -149,7 +150,7 @@ public class PrivilegeModelSaxReader extends DefaultHandler { private Set denyList; private Set allowList; - private Map privileges; + private Map privileges; /** * @@ -162,7 +163,7 @@ public class PrivilegeModelSaxReader extends DefaultHandler { * */ private void init() { - this.privileges = new HashMap(); + this.privileges = new HashMap(); this.text = null; @@ -204,7 +205,7 @@ public class PrivilegeModelSaxReader extends DefaultHandler { this.denyList.add(this.text.toString().trim()); } else if (qName.equals("Privilege")) { - Privilege privilege = new Privilege(this.privilegeName, this.privilegePolicy, this.allAllowed, + IPrivilege privilege = new PrivilegeImpl(this.privilegeName, this.privilegePolicy, this.allAllowed, this.denyList, this.allowList); this.privileges.put(this.privilegeName, privilege); diff --git a/src/test/java/ch/eitchnet/privilege/test/PrivilegeTest.java b/src/test/java/ch/eitchnet/privilege/test/PrivilegeTest.java index f1f9406af..06ee3ca96 100644 --- a/src/test/java/ch/eitchnet/privilege/test/PrivilegeTest.java +++ b/src/test/java/ch/eitchnet/privilege/test/PrivilegeTest.java @@ -36,8 +36,8 @@ import org.slf4j.LoggerFactory; import ch.eitchnet.privilege.base.AccessDeniedException; import ch.eitchnet.privilege.base.PrivilegeException; import ch.eitchnet.privilege.handler.PrivilegeHandler; -import ch.eitchnet.privilege.helper.CertificateThreadLocal; import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.PrivilegeContext; import ch.eitchnet.privilege.model.PrivilegeRep; import ch.eitchnet.privilege.model.Restrictable; import ch.eitchnet.privilege.model.RoleRep; @@ -47,6 +47,7 @@ import ch.eitchnet.privilege.test.model.TestRestrictable; import ch.eitchnet.privilege.test.model.TestSystemUserAction; import ch.eitchnet.privilege.test.model.TestSystemUserActionDeny; import ch.eitchnet.privilege.xml.InitializationHelper; +import ch.eitchnet.utils.helper.ArraysHelper; import ch.eitchnet.utils.helper.FileHelper; /** @@ -82,11 +83,13 @@ public class PrivilegeTest { @BeforeClass public static void init() throws Exception { try { + destroy(); + // copy configuration to tmp String pwd = System.getProperty("user.dir"); File origPrivilegeModelFile = new File(pwd + "/config/PrivilegeModel.xml"); - File tmpPrivilegeModelFile = new File(pwd + "/target/test/PrivilegeModel.xml"); + File tmpPrivilegeModelFile = new File(pwd + "/target/testPrivilege/PrivilegeModel.xml"); if (tmpPrivilegeModelFile.exists() && !tmpPrivilegeModelFile.delete()) { throw new RuntimeException("Tmp configuration still exists and can not be deleted at " + tmpPrivilegeModelFile.getAbsolutePath()); @@ -102,7 +105,7 @@ public class PrivilegeTest { throw new RuntimeException("Failed to copy " + origPrivilegeModelFile + " to " + tmpPrivilegeModelFile); } catch (Exception e) { - PrivilegeTest.logger.error(e.getMessage(), e); + logger.error(e.getMessage(), e); throw new RuntimeException("Initialization failed: " + e.getLocalizedMessage(), e); } @@ -114,7 +117,7 @@ public class PrivilegeTest { // delete temporary file String pwd = System.getProperty("user.dir"); - File tmpPrivilegeModelFile = new File(pwd + "/target/test/PrivilegeModel.xml"); + File tmpPrivilegeModelFile = new File(pwd + "/target/testPrivilege/PrivilegeModel.xml"); if (tmpPrivilegeModelFile.exists() && !tmpPrivilegeModelFile.delete()) { throw new RuntimeException("Tmp configuration still exists and can not be deleted at " + tmpPrivilegeModelFile.getAbsolutePath()); @@ -136,154 +139,139 @@ public class PrivilegeTest { File privilegeConfigFile = new File(pwd + "/config/Privilege.xml"); // initialize privilege - PrivilegeTest.privilegeHandler = InitializationHelper.initializeFromXml(privilegeConfigFile); + privilegeHandler = InitializationHelper.initializeFromXml(privilegeConfigFile); } catch (Exception e) { - PrivilegeTest.logger.error(e.getMessage(), e); + logger.error(e.getMessage(), e); throw new RuntimeException("Setup failed: " + e.getLocalizedMessage(), e); } } - private byte[] copyBytes(byte[] bytes) { - byte[] copy = new byte[bytes.length]; - System.arraycopy(bytes, 0, copy, 0, bytes.length); - return copy; + private void login(String username, byte[] password) { + Certificate certificate = privilegeHandler.authenticate(username, password); + Assert.assertTrue("Certificate is null!", certificate != null); + PrivilegeContext privilegeContext = privilegeHandler.getPrivilegeContext(certificate); + PrivilegeContext.set(privilegeContext); + } + + private void logout() { + try { + PrivilegeContext privilegeContext = PrivilegeContext.get(); + privilegeHandler.invalidateSession(privilegeContext.getCertificate()); + } catch (PrivilegeException e) { + String msg = "There is no PrivilegeContext currently bound to the ThreadLocal!"; + if (!e.getMessage().equals(msg)) + throw e; + } finally { + PrivilegeContext.set(null); + } } - /** - * @throws Exception - * if something goes wrong - */ @Test public void testAuthenticationOk() throws Exception { - - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - Assert.assertTrue("Certificate is null!", certificate != null); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + } finally { + logout(); + } } - /** - * @throws Exception - * if something goes wrong - */ @Test(expected = AccessDeniedException.class) public void testFailAuthenticationNOk() throws Exception { - - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_BAD)); - Assert.assertTrue("Certificate is null!", certificate != null); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_BAD)); + } finally { + logout(); + } } - /** - * @throws Exception - * if something goes wrong - */ @Test(expected = PrivilegeException.class) public void testFailAuthenticationPWNull() throws Exception { - - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, null); - Assert.assertTrue("Certificate is null!", certificate != null); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + login(ADMIN, null); + } finally { + logout(); + } } - /** - * @throws Exception - * if something goes wrong - */ @Test public void testAddRoleTemp() throws Exception { - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); - Map privilegeMap = new HashMap(); - RoleRep roleRep = new RoleRep(PrivilegeTest.ROLE_TEMP, privilegeMap); + Map privilegeMap = new HashMap(); + RoleRep roleRep = new RoleRep(ROLE_TEMP, privilegeMap); - PrivilegeTest.privilegeHandler.addOrReplaceRole(certificate, roleRep); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addOrReplaceRole(certificate, roleRep); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } - /** - * @throws Exception - * if something goes wrong - */ @Test public void testPerformRestrictableAsAdmin() throws Exception { + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - Assert.assertTrue("Certificate is null!", certificate != null); + // see if admin can perform restrictable + Restrictable restrictable = new TestRestrictable(); + PrivilegeContext.get().validateAction(restrictable); - // see if eitch can perform restrictable - Restrictable restrictable = new TestRestrictable(); - PrivilegeTest.privilegeHandler.actionAllowed(certificate, restrictable); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + } finally { + logout(); + } } /** * Tests if an action can be performed as a system user - * - * @throws Exception - * if something goes wrong */ @Test public void testPerformSystemRestrictable() throws Exception { - // create the action to be performed as a system user - TestSystemUserAction action = new TestSystemUserAction(PrivilegeTest.privilegeHandler); - - // and then perform the action - PrivilegeTest.privilegeHandler.runAsSystem(PrivilegeTest.SYSTEM_USER_ADMIN, action); + // create the action to be performed as a system user and then perform the action + TestSystemUserAction action = new TestSystemUserAction(); + privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); } /** * Checks that the system user can not perform a valid action, but illegal privilege - * - * @throws Exception - * if something goes wrong */ @Test(expected = PrivilegeException.class) public void testPerformSystemRestrictableFailPrivilege() throws Exception { + try { + // create the action to be performed as a system user + TestSystemUserActionDeny action = new TestSystemUserActionDeny(); - // create the action to be performed as a system user - TestSystemUserActionDeny action = new TestSystemUserActionDeny(PrivilegeTest.privilegeHandler); - - // and then perform the action - PrivilegeTest.privilegeHandler.runAsSystem(PrivilegeTest.SYSTEM_USER_ADMIN, action); + // and then perform the action + privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); + } finally { + logout(); + } } /** * System user may not login - * - * @throws Exception - * if something goes wrong */ @Test(expected = AccessDeniedException.class) public void testLoginSystemUser() throws Exception { - - PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.SYSTEM_USER_ADMIN, - PrivilegeTest.SYSTEM_USER_ADMIN.getBytes()); + try { + login(SYSTEM_USER_ADMIN, SYSTEM_USER_ADMIN.getBytes()); + } finally { + logout(); + } } @Test - public void testCertificateThreadLocal() { - - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - Assert.assertTrue("Certificate is null!", certificate != null); - - // set certificate into thread local - CertificateThreadLocal.getInstance().set(certificate); - - // see if bob can perform restrictable by returning certificate from CertificateThreadLocal - Restrictable restrictable = new TestRestrictable(); + public void testPrivilegeContext() { try { - PrivilegeTest.privilegeHandler.actionAllowed(CertificateThreadLocal.getInstance().get(), restrictable); + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Restrictable restrictable = new TestRestrictable(); + PrivilegeContext.get().validateAction(restrictable); } finally { - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + logout(); } } @@ -308,8 +296,6 @@ public class PrivilegeTest { *
  • perform restrictable as bob
  • * * - * @throws Exception - * if something goes wrong */ @Test public void testUserStory() throws Exception { @@ -334,216 +320,243 @@ public class PrivilegeTest { } private void performRestrictableAsBob() { - Certificate certificate; - // testPerformRestrictableAsBob - // Tests if the user bob, who now has AppUser role can perform restrictable - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - Assert.assertTrue("Certificate is null!", certificate != null); - // see if bob can perform restrictable - Restrictable restrictable = new TestRestrictable(); - PrivilegeTest.privilegeHandler.actionAllowed(certificate, restrictable); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testPerformRestrictableAsBob + // Tests if the user bob, who now has AppUser role can perform restrictable + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // see if bob can perform restrictable + Restrictable restrictable = new TestRestrictable(); + PrivilegeContext.get().validateAction(restrictable); + } finally { + logout(); + } } private void addRoleAppToBob() { - Certificate certificate; - // testAddAppRoleToBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - PrivilegeTest.privilegeHandler.addRoleToUser(certificate, PrivilegeTest.BOB, PrivilegeTest.ROLE_APP_USER); - PrivilegeTest.logger.info("Added " + PrivilegeTest.ROLE_APP_USER + " to " + PrivilegeTest.BOB); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testAddAppRoleToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, ROLE_APP_USER); + logger.info("Added " + ROLE_APP_USER + " to " + BOB); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void failPerformRestrictableAsBobNoRoleApp() { - Certificate certificate; - // testFailPerformRestrictableAsBob - // Tests if the user bob, who does not have AppUser role can perform restrictable - // this will fail as bob does not have role app - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - Assert.assertTrue("Certificate is null!", certificate != null); - // see if bob can perform restrictable - Restrictable restrictable = new TestRestrictable(); try { - PrivilegeTest.privilegeHandler.actionAllowed(certificate, restrictable); + // testFailPerformRestrictableAsBob + // Tests if the user bob, who does not have AppUser role can perform restrictable + // this will fail as bob does not have role app + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // see if bob can perform restrictable + Restrictable restrictable = new TestRestrictable(); + PrivilegeContext.get().validateAction(restrictable); Assert.fail("Should fail as bob does not have role app"); } catch (AccessDeniedException e) { String msg = "User bob does not have Privilege ch.eitchnet.privilege.test.model.TestRestrictable needed for Restrictable ch.eitchnet.privilege.test.model.TestRestrictable"; Assert.assertEquals(msg, e.getLocalizedMessage()); } finally { - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + logout(); } } private void authAsTed() { - Certificate certificate; - // testAuthAsTed - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.TED, copyBytes(PrivilegeTest.PASS_TED)); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testAuthAsTed + login(TED, ArraysHelper.copyOf(PASS_TED)); + } finally { + logout(); + } } private void tedChangesOwnPass() { - Certificate certificate; - // testTedChangesOwnPwd - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.TED, copyBytes(PrivilegeTest.PASS_DEF)); - PrivilegeTest.privilegeHandler.setUserPassword(certificate, PrivilegeTest.TED, - copyBytes(PrivilegeTest.PASS_TED)); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testTedChangesOwnPwd + login(TED, ArraysHelper.copyOf(PASS_DEF)); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED)); + } finally { + logout(); + } } private void setPassForTedAsBob() { - Certificate certificate; - // testSetTedPwdAsBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - Assert.assertTrue("Certificate is null!", certificate != null); - // set ted's password to default - PrivilegeTest.privilegeHandler.setUserPassword(certificate, PrivilegeTest.TED, - copyBytes(PrivilegeTest.PASS_DEF)); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testSetTedPwdAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // set ted's password to default + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_DEF)); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void failAuthAsTedNoPass() { - // testFailAuthAsTedNoPass - // Will fail because user ted has no password try { - PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.TED, copyBytes(PrivilegeTest.PASS_TED)); + // testFailAuthAsTedNoPass + // Will fail because user ted has no password + login(TED, ArraysHelper.copyOf(PASS_TED)); org.junit.Assert.fail("User Ted may not authenticate because the user has no password!"); } catch (PrivilegeException e) { String msg = "User ted has no password and may not login!"; Assert.assertEquals(msg, e.getMessage()); + } finally { + logout(); } } private void addTedAsBob() { - Certificate certificate; - UserRep userRep; - // testAddUserTedAsBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - Assert.assertTrue("Certificate is null!", certificate != null); - // let's add a new user ted - HashSet roles = new HashSet(); - roles.add(PrivilegeTest.ROLE_USER); - userRep = new UserRep("2", PrivilegeTest.TED, "Ted", "Newman", UserState.ENABLED, roles, null, - new HashMap()); - PrivilegeTest.privilegeHandler.addOrReplaceUser(certificate, userRep, null); - PrivilegeTest.logger.info("Added user " + PrivilegeTest.TED); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + UserRep userRep; + // testAddUserTedAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // let's add a new user ted + HashSet roles = new HashSet(); + roles.add(ROLE_USER); + userRep = new UserRep("2", TED, "Ted", "Newman", UserState.ENABLED, roles, null, + new HashMap()); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addOrReplaceUser(certificate, userRep, null); + logger.info("Added user " + TED); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void addRoleAdminToBob() { - Certificate certificate; - // testAddAdminRoleToBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - PrivilegeTest.privilegeHandler.addRoleToUser(certificate, PrivilegeTest.BOB, - PrivilegeHandler.PRIVILEGE_ADMIN_ROLE); - PrivilegeTest.logger.info("Added " + PrivilegeHandler.PRIVILEGE_ADMIN_ROLE + " to " + PrivilegeTest.ADMIN); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testAddAdminRoleToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, PrivilegeHandler.PRIVILEGE_ADMIN_ROLE); + logger.info("Added " + PrivilegeHandler.PRIVILEGE_ADMIN_ROLE + " to " + ADMIN); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void failAddTedAsBobNotAdmin() { - Certificate certificate; - UserRep userRep; - // testFailAddUserTedAsBob - // Will fail because user bob does not have admin rights - // auth as Bob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - // let's add a new user Ted - userRep = new UserRep("1", PrivilegeTest.TED, "Ted", "And then Some", UserState.NEW, new HashSet(), - null, new HashMap()); + Certificate certificate = null; try { - PrivilegeTest.privilegeHandler.addOrReplaceUser(certificate, userRep, null); + UserRep userRep; + // testFailAddUserTedAsBob + // Will fail because user bob does not have admin rights + // auth as Bob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + // let's add a new user Ted + userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, new HashSet(), null, + new HashMap()); + certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addOrReplaceUser(certificate, userRep, null); Assert.fail("User bob may not add a user as bob does not have admin rights!"); } catch (PrivilegeException e) { - String msg = "User does not have PrivilegeAdmin role! Certificate: " + certificate.toString(); + String msg = "User does not have PrivilegeAdmin role! Certificate: " + certificate; Assert.assertEquals(msg, e.getMessage()); } finally { - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + logout(); } } private void authAsBob() { - Certificate certificate; - // testAuthAsBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testAuthAsBob + login(BOB, ArraysHelper.copyOf(PASS_BOB)); + } finally { + logout(); + } } private void addRoleUserToBob() { - Certificate certificate; - // testAddRoleUserToBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - PrivilegeTest.privilegeHandler.addRoleToUser(certificate, PrivilegeTest.BOB, PrivilegeTest.ROLE_USER); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testAddRoleUserToBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addRoleToUser(certificate, BOB, ROLE_USER); + privilegeHandler.persist(certificate); + logout(); + } finally { + logout(); + } } private void addRoleUser() { - Certificate certificate; - // add role user - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - Map privilegeMap = new HashMap(); - RoleRep roleRep = new RoleRep(PrivilegeTest.ROLE_USER, privilegeMap); - PrivilegeTest.privilegeHandler.addOrReplaceRole(certificate, roleRep); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // add role user + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Map privilegeMap = new HashMap(); + RoleRep roleRep = new RoleRep(ROLE_USER, privilegeMap); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addOrReplaceRole(certificate, roleRep); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void failAuthAsBobNoRole() { - // testFailAuthUserBob - // Will fail as user bob has no role try { - PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); + // testFailAuthUserBob + // Will fail as user bob has no role + privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB)); org.junit.Assert.fail("User Bob may not authenticate because the user has no role"); } catch (PrivilegeException e) { String msg = "User bob does not have any roles defined!"; Assert.assertEquals(msg, e.getMessage()); + } finally { + logout(); } } private void enableBob() { - Certificate certificate; - // testEnableUserBob - certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); - PrivilegeTest.privilegeHandler.setUserState(certificate, PrivilegeTest.BOB, UserState.ENABLED); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + try { + // testEnableUserBob + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.setUserState(certificate, BOB, UserState.ENABLED); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } private void failAuthAsBobNotEnabled() { - // testFailAuthAsBob - // Will fail because user bob is not yet enabled try { - PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.BOB, copyBytes(PrivilegeTest.PASS_BOB)); + // testFailAuthAsBob + // Will fail because user bob is not yet enabled + privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB)); org.junit.Assert.fail("User Bob may not authenticate because the user is not yet enabled!"); } catch (PrivilegeException e) { String msg = "User bob does not have state ENABLED and can not login!"; Assert.assertEquals(msg, e.getMessage()); + } finally { + logout(); } } private void addBobAsAdmin() { - Certificate certificate = PrivilegeTest.privilegeHandler.authenticate(PrivilegeTest.ADMIN, - copyBytes(PrivilegeTest.PASS_ADMIN)); + try { + login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); - // let's add a new user bob - UserRep userRep = new UserRep("1", PrivilegeTest.BOB, "Bob", "Newman", UserState.NEW, new HashSet(), - null, new HashMap()); - PrivilegeTest.privilegeHandler.addOrReplaceUser(certificate, userRep, null); - PrivilegeTest.logger.info("Added user " + PrivilegeTest.BOB); + // let's add a new user bob + UserRep userRep = new UserRep("1", BOB, "Bob", "Newman", UserState.NEW, new HashSet(), null, + new HashMap()); + Certificate certificate = PrivilegeContext.get().getCertificate(); + privilegeHandler.addOrReplaceUser(certificate, userRep, null); + logger.info("Added user " + BOB); - // set bob's password - PrivilegeTest.privilegeHandler.setUserPassword(certificate, PrivilegeTest.BOB, - copyBytes(PrivilegeTest.PASS_BOB)); - PrivilegeTest.logger.info("Set Bob's password"); - privilegeHandler.persist(certificate); - PrivilegeTest.privilegeHandler.invalidateSession(certificate); + // set bob's password + privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_BOB)); + logger.info("Set Bob's password"); + privilegeHandler.persist(certificate); + } finally { + logout(); + } } } diff --git a/src/test/java/ch/eitchnet/privilege/test/XmlTest.java b/src/test/java/ch/eitchnet/privilege/test/XmlTest.java index da7e2a1b5..23db59a65 100644 --- a/src/test/java/ch/eitchnet/privilege/test/XmlTest.java +++ b/src/test/java/ch/eitchnet/privilege/test/XmlTest.java @@ -23,6 +23,7 @@ package ch.eitchnet.privilege.test; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -40,9 +41,10 @@ import org.slf4j.LoggerFactory; import ch.eitchnet.privilege.handler.DefaultEncryptionHandler; import ch.eitchnet.privilege.handler.XmlPersistenceHandler; +import ch.eitchnet.privilege.model.IPrivilege; import ch.eitchnet.privilege.model.UserState; -import ch.eitchnet.privilege.model.internal.Privilege; import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel; +import ch.eitchnet.privilege.model.internal.PrivilegeImpl; import ch.eitchnet.privilege.model.internal.Role; import ch.eitchnet.privilege.model.internal.User; import ch.eitchnet.privilege.xml.PrivilegeConfigDomWriter; @@ -71,6 +73,7 @@ public class XmlTest { */ @BeforeClass public static void init() throws Exception { + destroy(); File tmpDir = new File("target/test"); if (tmpDir.exists()) @@ -179,7 +182,7 @@ public class XmlTest { Map propertyMap; Set userRoles; - Map privilegeMap; + Map privilegeMap; List users = new ArrayList(); propertyMap = new HashMap(); @@ -197,16 +200,17 @@ public class XmlTest { propertyMap)); List roles = new ArrayList(); - privilegeMap = new HashMap(); - privilegeMap.put("priv1", new Privilege("priv1", "DefaultPrivilege", true, null, null)); + Set list = Collections.emptySet(); + privilegeMap = new HashMap(); + privilegeMap.put("priv1", new PrivilegeImpl("priv1", "DefaultPrivilege", true, list, list)); roles.add(new Role("role1", privilegeMap)); - privilegeMap = new HashMap(); + privilegeMap = new HashMap(); Set denyList = new HashSet(); denyList.add("myself"); Set allowList = new HashSet(); allowList.add("other"); - privilegeMap.put("priv2", new Privilege("priv2", "DefaultPrivilege", false, denyList, allowList)); + privilegeMap.put("priv2", new PrivilegeImpl("priv2", "DefaultPrivilege", false, denyList, allowList)); roles.add(new Role("role2", privilegeMap)); File modelFile = new File("./target/test/PrivilegeModelTest.xml"); @@ -214,6 +218,6 @@ public class XmlTest { configSaxWriter.write(); String fileHash = StringHelper.getHexString(FileHelper.hashFileSha256(modelFile)); - Assert.assertEquals("8E1E82278162F21B1654C2E059570BBCB3CB63B053C1DD784BC8E225E8CFD04F", fileHash); + Assert.assertEquals("9007F172BBD7BA51BA3E67199CE0AFCBC8645AF0AC02028ABE54BA6A2FC134B0", fileHash); } } diff --git a/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserAction.java b/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserAction.java index f247d680b..c86a5fdb0 100644 --- a/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserAction.java +++ b/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserAction.java @@ -19,34 +19,20 @@ */ package ch.eitchnet.privilege.test.model; -import ch.eitchnet.privilege.handler.PrivilegeHandler; import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.PrivilegeContext; /** * @author Robert von Burg - * + * */ public class TestSystemUserAction implements SystemUserAction { - private PrivilegeHandler handler; - - /** - * - */ - public TestSystemUserAction(PrivilegeHandler handler) { - this.handler = handler; - } - - /** - * @see ch.eitchnet.privilege.handler.SystemUserAction#execute(ch.eitchnet.privilege.model.Certificate) - */ @Override - public void execute(Certificate certificate) { - + public void execute(PrivilegeContext context) { TestSystemRestrictable restrictable = new TestSystemRestrictable(); - - this.handler.actionAllowed(certificate, restrictable); + PrivilegeContext.set(context); + context.validateAction(restrictable); + PrivilegeContext.set(null); } - } diff --git a/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserActionDeny.java b/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserActionDeny.java index 14f6e566a..d8ed59616 100644 --- a/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserActionDeny.java +++ b/src/test/java/ch/eitchnet/privilege/test/model/TestSystemUserActionDeny.java @@ -19,9 +19,8 @@ */ package ch.eitchnet.privilege.test.model; -import ch.eitchnet.privilege.handler.PrivilegeHandler; import ch.eitchnet.privilege.handler.SystemUserAction; -import ch.eitchnet.privilege.model.Certificate; +import ch.eitchnet.privilege.model.PrivilegeContext; /** * @author Robert von Burg @@ -29,22 +28,9 @@ import ch.eitchnet.privilege.model.Certificate; */ public class TestSystemUserActionDeny implements SystemUserAction { - private PrivilegeHandler handler; - - /** - * - */ - public TestSystemUserActionDeny(PrivilegeHandler handler) { - this.handler = handler; - } - - /** - * @see ch.eitchnet.privilege.handler.SystemUserAction#execute(ch.eitchnet.privilege.model.Certificate) - */ @Override - public void execute(Certificate certificate) { - + public void execute(PrivilegeContext privilegeContext) { TestRestrictable restrictable = new TestRestrictable(); - this.handler.actionAllowed(certificate, restrictable); + privilegeContext.validateAction(restrictable); } }