A few recipes for reprocessing messages in Dead-Letter-Queue using ActiveMQ
February 3rd, 2010
Messaging based asynchronous processing is a key component of any complexed software especially in transactional environment. There are a number of solutions that provide high performance and reliable messaging in Java space such as ActiveMQ, FUSE broker, JBossMQ, SonicMQ, Weblogic, Websphere, Fiorano, etc. These providers support JMS specification, which provides abstraction for queues, message providers and message consumers. In this blog, I will go over some recipes for recovering messages from dead letter queue when using ActiveMQ.
What is Dead Letter Queue
Generally, when a consumer fails to process a message within a transaction or does not send acknowledgement back to the broker, the message is put back to the queue. The message is then delivered upto certain number of times based on configuration and finally the message is put to dead letter queue when that limit is exceeded. The ActiveMQ documentation recommends following settings for defining dead letter queues:
<broker...>
<destinationPolicy>
<policyMap>
<policyEntries>
<!-- Set the following policy on all queues using the '>' wildcard -->
<policyEntry queue=">">
<deadLetterStrategy>
<individualDeadLetterStrategy
queuePrefix="DLQ." useQueueForQueueMessages="true" />
</deadLetterStrategy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
...
</broker>
and you can control redlivery policy as follows:
RedeliveryPolicy policy = connection.getRedeliveryPolicy(); policy.setInitialRedeliveryDelay(500); policy.setBackOffMultiplier(2); policy.setUseExponentialBackOff(true); policy.setMaximumRedeliveries(2);
It is important that you create dlq per queue, otherwise ActiveMQ puts them into a single dead letter queue.
Getting the QueueViewMBean Handle
ActiveMQ provides QueueViewMBean to invoke administration APIs on the queues. The easiest way to get this handle is to use BrokerFacadeSupport class, which is extended by RemoteJMXBrokerFacade and LocalBrokerFacade. You can use RemoteJMXBrokerFacade if you are connecting to remote ActiveMQ server, e.g. here is Spring configuration for setting it up:
<bean id="brokerQuery" class="org.apache.activemq.web.RemoteJMXBrokerFacade" autowire="constructor" destroy-method="shutdown">
<property name="configuration">
<bean class="org.apache.activemq.web.config.SystemPropertiesConfiguration"/>
</property>
<property name="brokerName"><null/></property>
</bean>
Alternatively, you can use LocalBrokerFacade if you are running embedded ActiveMQ server, e.g. below is Spring configuration for it:
<bean id="brokerQuery" class="org.apache.activemq.web.LocalBrokerFacade" autowire="constructor" scope="prototype"/>
Getting number of messages from the queue
Once you got handle to QueueViewMBean, you can use following API to find the number of messages in the queue:
1 public long getQueueSize(final String dest) { 2 try { 3 return brokerQuery.getQueue(dest).getQueueSize(); 4 } catch (Exception e) { 5 throw new RuntimeException(e); 6 } 7 } 8
Copying Messages using JMS APIs
The JMS specification provides APIs to browse queue in read mode and then you can send the messages to another queue, e.g.
1 import java.util.Enumeration; 2 3 import javax.jms.Connection; 4 import javax.jms.ConnectionFactory; 5 import javax.jms.JMSException; 6 import javax.jms.Message; 7 import javax.jms.Queue; 8 import javax.jms.QueueBrowser; 9 import javax.jms.Session; 10 import javax.jms.TextMessage; 11 import javax.management.openmbean.CompositeData; 12 13 import org.apache.activemq.broker.jmx.QueueViewMBean; 14 import org.apache.activemq.web.BrokerFacadeSupport; 15 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.jms.core.BrowserCallback; 17 import org.springframework.jms.core.JmsTemplate; 18 import org.springframework.jms.core.MessageCreator; 19 20 public class DlqReprocessor { 21 @Autowired 22 private JmsTemplate jmsTemplate; 23 24 @Autowired 25 BrokerFacadeSupport brokerQuery; 26 27 @Autowired 28 ConnectionFactory connectionFactory; 29 30 31 @SuppressWarnings("unchecked") 32 void redeliverDLQUsingJms(final String brokerName, final String from, 33 final String to) { 34 Connection connection = null; 35 Session session = null; 36 37 try { 38 connection = connectionFactory.createConnection(); 39 connection.start(); 40 session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 41 Queue dlq = session.createQueue(from); 42 QueueBrowser browser = session.createBrowser(dlq); 43 44 Enumeration<Message> e = browser.getEnumeration(); 45 46 while (e.hasMoreElements()) { 47 Message message = e.nextElement(); 48 final String messageBody = ((TextMessage) message).getText(); 49 jmsTemplate.send(to, new MessageCreator() { 50 @Override 51 public Message createMessage(final Session session) 52 throws JMSException { 53 return session.createTextMessage(messageBody); 54 } 55 }); 56 } 57 } catch (Exception e) { 58 throw new RuntimeException(e); 59 } finally { 60 try { 61 session.close(); 62 } catch (Exception e) { 63 } 64 try { 65 connection.close(); 66 } catch (Exception e) { 67 } 68 } 69 } 70 // . . . 71 } 72
The downside of above approach is that it leaves the original messages in the dead letter queue.
Copying Messages using Spring’s JmsTemplate APIs
You can effectively do the same thing with JmsTemplate provided by Spring with a bit less code, e.g.
1 void redeliverDLQUsingJmsTemplateBrowse(final String from, final String to) { 2 try { 3 jmsTemplate.browse(from, new BrowserCallback() { 4 5 @SuppressWarnings("unchecked") 6 @Override 7 public Object doInJms(Session session, QueueBrowser browser) 8 throws JMSException { 9 Enumeration<Message> e = browser.getEnumeration(); 10 while (e.hasMoreElements()) { 11 Message message = e.nextElement(); 12 final String messageBody = ((TextMessage) message) 13 .getText(); 14 jmsTemplate.send(to, new MessageCreator() { 15 @Override 16 public Message createMessage(final Session session) 17 throws JMSException { 18 return session.createTextMessage(messageBody); 19 } 20 }); 21 } 22 return null; 23 } 24 }); 25 } catch (Exception e) { 26 throw new RuntimeException(e); 27 } 28 } 29
Moving Messages using receive/send APIs
As I mentioned, the above approaches leave messages in the DLQ, which may not be what you want. Thus, another simple approach would be to consume messages from the dead letter queue and send it to another,e.g.
1 public void redeliverDLQUsingJmsTemplateReceive(final String from, 2 final String to) { 3 try { 4 jmsTemplate.setReceiveTimeout(100); 5 Message message = null; 6 while ((message = jmsTemplate.receive(from)) != null) { 7 final String messageBody = ((TextMessage) message).getText(); 8 jmsTemplate.send(to, new MessageCreator() { 9 @Override 10 public Message createMessage(final Session session) 11 throws JMSException { 12 return session.createTextMessage(messageBody); 13 } 14 }); 15 } 16 } catch (Exception e) { 17 throw new RuntimeException(e); 18 } 19 } 20
Moving Messages using ActiveMQ’s API
Finally, the best approach I found waas to use ActiveMQ’s APIs to move messags, e.g.
1 public void redeliverDLQUsingJMX(final String brokerName, final String from, 2 final String to) { 3 try { 4 final QueueViewMBean queue = brokerQuery.getQueue(from); 5 for (int i = 0; i < 10 && queue.getQueueSize() > 0; i++) { 6 CompositeData[] compdatalist = queue.browse(); 7 for (CompositeData cdata : compdatalist) { 8 String messageID = (String) cdata.get("JMSMessageID"); 9 queue.moveMessageTo(messageID, to); 10 } 11 } 12 } catch (Exception e) { 13 throw new RuntimeException(e); 14 } 15 } 16
I have been using this approach and have found to be reliable for reprocessing dead letter queue, though these techniques an also be used for general queues. I am sure there are tons of alternatives including using full-fledged enterprise service bus route. Let me know if you have interesting solutions to this problem.
This is continuation of my previous blog on my open source project PlexRBAC for managing role based access control. Last time, I covered REST APIs and in this blog I will cover internal domain model, RBAC APIs in Java and examples of instance or dynamic based security.
Layers
PlexRBAC consists of following layers
Business Domain Layer
This layer defines core classes that are part of the RBAC based security domain such as:
- Domain – As described previously, the domain allows you to support multiple applications or realms.
- Subject – The subject represents users who are defined in an application.
- Role – A role represents job title or function.
- Permission – A permission is composed of operation, target and an expression that is used for dynamic or instance based security.
- SecurityError – Upon a permission failure, you can choose to store them in the database using SecurityError.
Repository Layer
This layer is responsible for accessing or storing above objects in the database. PlexRBAC uses Berkley DB for persistence and each domain is stored as a separate database, which allows you to segregate permissions and roles for distinct domains. Following are list of repositories supported by PlexRBAC:
- DomainRepository – provides database access for Domains.
- PermissionRepository – provides database access for Permissions.
- SubjectRepository – provides database access for Subjects.
- SecurityErrorRepository – provides database access for SecurityErrors.
- RoleRepository – provides database access for Roles.
- SecurityMappingRepository – provides APIs to map permissions with roles and to map subject with roles.
- RepositoryFactory – provides factory methods to create above repositories.
Security Layer
This class defines PermissionManager for authorizing permissions.
Evaluation Layer
This layer proivdes evaluation engine for instance based security.
Service Layer
This layer defines REST services such as:
- DomainService – this service provides REST APIs for accessing Domains.
- PermissionService – this service provides REST APIs for accessing Permissions.
- SubjectService – this service provides REST APIs for accessing Subjects.
- RoleService – this service provides REST APIs for accessing Roles.
- AuthenticationService – this service provides REST APIs for authenticating users.
- AuthorizationService – this service provides REST APIs for authorizing permissions.
- RolePermissionService – this service provides REST APIs for mapping permissions with roles.
- SubjectRolesService – this service provides REST APIs for mapping subjects with roles.
JMX Layer
This layer defines JMX helper classes for managing services and configuration remotely.
Caching Layer
This layer provides caching security permissions to improve performance.
Metrics Layer
This layer provides performance measurement classes such as Timing class to measure method invocation benchmarks.
Utility Layer
This layer provides helper classes.
Web Layer
This layer provides filters for enforcing authentication and authorization when accessing REST APIs.
Example
Let’s use the same example that we described last time but with addition of instance based security. Let’s assume there are five roles: Teller, Customer-Service-Representative (CSR), Account, AccountingManager and LoanOfficer, where
- A teller can modify customer deposit accounts — but only if customer and teller live in same region
- A customer service representative can create or delete customer deposit accounts — but only if customer and teller live in same region
- An accountant can create general ledger reports — but only if year is == current year
- An accounting manager can modify ledger-posting rules — but only if year is == current year
- A loan officer can create and modify loan accounts – but only if account balance is < 10000
In addition, following classes will be used to add domain specific security:
1 2 class User { 3 4 private String id; 5 private String region; 6 7 User() { 8 } 9 10 public User(String id, String region) { 11 this.id = id; 12 this.region = region; 13 } 14 15 public void setRegion(String region) { 16 this.region = region; 17 } 18 19 public String getRegion() { 20 return region; 21 } 22 23 public void setId(String id) { 24 this.id = id; 25 } 26 27 public String getId() { 28 return id; 29 } 30 } 31 32 class Customer extends User { 33 34 public Customer(String id, String region) { 35 super(id, region); 36 } 37 } 38 39 class Employee extends User { 40 41 public Employee(String id, String region) { 42 super(id, region); 43 } 44 } 45 46 class Account { 47 48 private String id; 49 private double balance; 50 51 Account() { 52 } 53 54 public Account(String id, double balance) { 55 this.id = id; 56 this.balance = balance; 57 } 58 59 /** 60 * @return the id 61 */ 62 public String getId() { 63 return id; 64 } 65 66 /** 67 * @param id 68 * the id to set 69 */ 70 public void setId(String id) { 71 this.id = id; 72 } 73 74 public void setBalance(double balance) { 75 this.balance = balance; 76 } 77 78 public double getBalance() { 79 return balance; 80 } 81 } 82 83
Bootstrapping
Let’s create handle to repository-factory as:
1 2 private static final String TEST_DB_DIR = "test_db_dir_perms"; 3 RepositoryFactory repositoryFactory = new RepositoryFactoryImpl(TEST_DB_DIR);
And instance of permission manager as:
1 PermissionManager permissionManager = new PermissionManagerImpl(repositoryFactory, 2 new JavascriptEvaluator());
Creating a domain
Now, let’s create a domain for banking:
1 private static final String BANKING = "banking"; 2 repositoryFactory.getDomainRepository().save(new Domain(BANKING, ""));
Creating Users
Next step is to create users for the domain or application so let’s define accounts for tom, cassy, ali, mike and larry, i.e.,
1 final SubjectRepository subjectRepo = repositoryFactory 2 .getSubjectRepository(BANKING); 3 Subject tom = subjectRepo.save(new Subject("tom", "pass")); 4 Subject cassy = subjectRepo.save(new Subject("cassy", "pass")); 5 Subject ali = subjectRepo.save(new Subject("ali", "pass")); 6 Subject mike = subjectRepo.save(new Subject("mike", "pass")); 7 Subject larry = subjectRepo.save(new Subject("larry", "pass")); 8
Creating Roles
Now, we will create roles for Teller, CSR, Accountant, AccountManager and LoanManager:
1 final RoleRepository roleRepo = repositoryFactory 2 .getRoleRepository(BANKING); 3 Role employee = roleRepo.save(new Role("Employee")); 4 Role teller = roleRepo.save(new Role("Teller", employee)); 5 Role csr = roleRepo.save(new Role("CSR", teller)); 6 Role accountant = roleRepo.save(new Role("Accountant", employee)); 7 Role accountantMgr = roleRepo.save(new Role("AccountingManager", 8 accountant)); 9 Role loanOfficer = roleRepo 10 .save(new Role("LoanOfficer", accountantMgr)); 11
Creating Permissions
We can then create new permissions and save them in the database as follows:
1 final PermissionRepository permRepo = repositoryFactory 2 .getPermissionRepository(BANKING); 3 Permission cdDeposit = permRepo.save(new Permission("(create|delete)", 4 "DepositAccount", 5 "employee.getRegion().equals(customer.getRegion())")); // 1 6 Permission ruDeposit = permRepo.save(new Permission("(read|modify)", 7 "DepositAccount", 8 "employee.getRegion().equals(customer.getRegion())")); // 2 9 Permission cdLoan = permRepo.save(new Permission("(create|delete)", 10 "LoanAccount", "account.getBalance() < 10000")); // 3 11 Permission ruLoan = permRepo.save(new Permission("(read|modify)", 12 "LoanAccount", "account.getBalance() < 10000")); // 4 13 14 Permission rdLedger = permRepo.save(new Permission("(read|create)", 15 "GeneralLedger", "year == new Date().getFullYear()")); // 5 16 17 Permission rGlpr = permRepo 18 .save(new Permission("read", "GeneralLedgerPostingRules", 19 "year == new Date().getFullYear()")); // 6 20 21 Permission cmdGlpr = permRepo.save(new Permission( 22 "(create|modify|delete)", "GeneralLedgerPostingRules", 23 "year == new Date().getFullYear()")); // 7 24
Mapping Subjects/Permissions to Roles
Now we will map subjects to roles as follows:
1 final SecurityMappingRepository smr = repositoryFactory 2 .getSecurityMappingRepository(BANKING); 3 4 // Mapping Users to Roles 5 smr.addRolesToSubject(tom, teller); 6 smr.addRolesToSubject(cassy, csr); 7 smr.addRolesToSubject(ali, accountant); 8 smr.addRolesToSubject(mike, accountantMgr); 9 smr.addRolesToSubject(larry, loanOfficer); 0
Then we will map permissions to roles as follows:
1 smr.addPermissionsToRole(teller, ruDeposit); 2 smr.addPermissionsToRole(csr, cdDeposit); 3 smr.addPermissionsToRole(accountant, rdLedger); 4 smr.addPermissionsToRole(accountant, ruLoan); 5 smr.addPermissionsToRole(accountantMgr, cdLoan); 6 smr.addPermissionsToRole(accountantMgr, rGlpr); 7 smr.addPermissionsToRole(loanOfficer, cmdGlpr); 8
Authorization
Now the fun part of authorization, let’s check if user “tom” can view deposit-accounts, e.g.
1 public static Map<String, Object> toMap(final Object... keyValues) { 2 Map<String, Object> map = new HashMap<String, Object>(); 3 for (int i = 0; i < keyValues.length - 1; i += 2) { 4 map.put(keyValues[i].toString(), keyValues[i + 1]); 5 } 6 return map; 7 } 8 @Test 9 public void testReadDepositByTeller() { 10 initDatabase(); 11 permissionManager.check(new PermissionRequest(BANKING, "tom", "read", 12 "DepositAccount", toMap("employee", new Employee("tom", 13 "west"), "customer", new Customer("zak", "west")))); 14 } 15 16
Note that above test method builds a PermissionRequest that encapsulates domain, subject, operation, target and context and then calls check method of SecurityManager, which throws SecurityException if permission fails.
Then we check if tom, the teller can delete deposit-account, e.g.
1 @Test(expected = SecurityException.class) 2 public void testDeleteByTeller() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "tom", "delete", 5 "DepositAccount", toMap("employee", new Employee("tom", 6 "west"), "customer", new Customer("zak", "west")))); 7 } 8
Which would throw security exception.
Now let’s check if cassy, the CSR can delete deposit-account, e.g.
1 @Test 2 public void testDeleteByCsr() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "cassy", 5 "delete", "DepositAccount", toMap("employee", 6 new Employee("cassy", "west"), "customer", 7 new Customer("zak", "west")))); 0
Which works as CSR have permissions for deleting deposit-account. Now, let’s check if ali, the accountant can view general-ledger, e.g.
1 @Test 2 public void testReadLedgerByAccountant() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "ali", "read", 5 "GeneralLedger", toMap("year", 2010, "account", 6 new Account("zak", 500)))); 7 } 8 9
Which works as expected. Next we check if ali can delete general-ledger:
1 @Test(expected = SecurityException.class) 2 public void testDeleteLedgerByAccountant() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "ali", "delete", 5 "GeneralLedger", toMap("year", 2010, "account", 6 new Account("zak", 500)))); 7 } 8 9
Which would fail as only account-manager can delete. Next we check if mike, the account-manager can create general-ledger, e.g.
1 @Test 2 public void testCreateLedgerByAccountantManager() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "mike", 5 "create", "GeneralLedger", toMap("year", 2010, 6 "account", new Account("zak", 500)))); 7 } 8
Which works as expected. Now we check if mike can create posting-rules of general-ledger, e.g.
1 @Test(expected = SecurityException.class) 2 public void testPostLedgingRulesByAccountantManager() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "mike", 5 "create", "GeneralLedgerPostingRules", toMap("year", 6 2010, "account", new Account("zak", 500)))); 7 } 8
Which fails authorization. Then we check if larry, the loan officer can create posting-rules of general-ledger, e.g.
1 @Test 2 public void testPostLedgingRulesByLoanManager() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "larry", 5 "create", "GeneralLedgerPostingRules", toMap("year", 6 2010, "account", new Account("zak", 500)))); 7 } 8
Which works as expected. Now, let’s check the same permission but with different year, e.g.
1 @Test(expected = SecurityException.class) 2 public void testPostLedgingRulesByLoanManagerWithExceededAmount() { 3 initDatabase(); 4 permissionManager.check(new PermissionRequest(BANKING, "larry", 5 "create", "GeneralLedgerPostingRules", IDUtils.toMap("year", 6 2011))); 7 } 8
Which fails as year doesn’t match.
Summary
Above examples demonstrate how PlexRBAC API can be used along with instance or dynamic based security. In next post, I will describe caching and how PlexRBAC can be integrated with J2EE and Spring security.
Overview
In my last blog I described core pieces of a security system and mentioned a new open source project PlexRBAC I recently started to provide Role Based Security both as a REST service and Java library. In this post, I will go over the some of the features that are now available. This project is based on my experience with a number of home built solutions for RBAC and standard J2EE solutions. However, a key differentiator is that it adds instance based security or context based security that adds dynamic access control. The role based security consists of following components:
Domain
Though, domain is strictly not part of role based security but RBAC provides segregation of security policies by domains, where a domain can represent a security realm or an application.
Subject
The subject represents users who are defined in an application.
Role
A role represents job title or function. A subject or user belongs to one or more roles. One of key feature of PlexRBAC is that roles support inheritance where a role can have one or more roles. This helps define security policies that follow “don’t repeat yourself” or DRY.
Permission
A permission consists of two sub parts: operation and target, where operation is a “verb” that describes action and target represents “object” that is acted upon. All permissions are assigned to roles. In PlexRBAC, permissions also contains an expression which is evaluated to check dynamic security. PlexRBAC allows Javascript based expressions and provides access to runtime request parameters. Finally, PlexRBAC offers regular expressions for both operations and target, so you can define operations like “(read|write|create|delete)” or “read*”, etc.
Following diagram shows the relationship between these components:

Getting Started
PlexRBAC depends on Java 1.6+ and Maven 2.0+. You can download the project using git:
git clone git@github.com:bhatti/PlexRBAC.git
Then you can start the REST based web service within Jetty by typing:
mvn jetty:run-war
The service will listen on port 8080 and you can test it with curl.
Authentication
Though, PlexRBAC is not designed for authentication but it provides Basic authentication and all administration APIs are protected with the authentication. By default, it uses an account “super_admin” with password “changeme”, which you can modify with configurations. Also, as PlexRBAC supports domains to segregates security policies, subjects are also restricted to the domains where they are defined.
REST APIs
Following are APIs defined in PlexRBAC:
Domains
- GET /api/security/domains – returns list of all domains in JSON format.
- GET /api/security/domains/{domain-id} – returns details of given domain in JSON format.
- PUT /api/security/domains/{domain-id} with body of domain details in JSON format.
- DELETE /api/security/domains – deletes all domains.
- DELETE /api/security/domains/{domain-id} – deletes domain identified by domain-id.
Subjects
- GET /api/security/subjects/{domain-id} – returns list of all subjects in domain identified by domain-id in JSON format.
- GET /api/security/subjects/{domain-id}/{id} – returns details of given subject identified by id in given domain.
- PUT /api/security/subjects/{domain-id}/{id} with body of subject details in JSON format.
- DELETE /api/security/subjects/{domain-id} – deletes all subjects in given domain.
- DELETE /api/security/subjects/{domain-id}/{id} – deletes subject identified by id.
Roles
- GET /api/security/roles/{domain-id} – returns list of all roles in domain identified by domain-id in JSON format.
- GET /api/security/roles/{domain-id}/{id} – returns details of given role identified by id in given domain.
- PUT /api/security/roles/{domain-id}/{id} with body of role details in JSON format.
- DELETE /api/security/roles/{domain-id} – deletes all roles in given domain.
- DELETE /api/security/roles/{domain-id}/{id} – deletes role identified by id.
Permissions
- GET /api/security/permissions/{domain-id} – returns list of all permissions in domain identified by domain-id in JSON format.
- GET /api/security/permissions/{domain-id}/{id} – returns details of given permission identified by id in given domain.
- POST /api/security/permissions/{domain-id} with body of permission details in JSON format. Note that this API uses POST instead of PUT as the id will be assigned by the server.
- DELETE /api/security/permissions/{domain-id} – deletes all permissions in given domain.
- DELETE /api/security/permissions/{domain-id}/{id} – deletes permission identified by id.
Mapping of Roles and Permissions
- PUT /api/security/role_perms/{domain-id}/{role-id} – adds permissions identified by permissionIds that stores list of permission-ids in JSON format. Note that permissionIds is passed as a form parameter.
- DELETE /api/security/role_perms/{domain-id}/{role-id} – removes permissions identified by permissionIds that stores list of permission-ids in JSON format. Note that permissionIds is passed as a form parameter.
Mapping of Subjects and Roles
- PUT /api/security/subject_roles/{domain-id}/{subject-id} – adds roles identified by rolenames that stores list of role-ids in JSON format. Note that rolenames is passed as a form parameter.
- DELETE /api/security/subject_roles/{domain-id}/{subject-id} – removes roles identified by rolenames that stores list of role-ids in JSON format. Note that rolenames is passed as a form parameter.
Authorization
- GET /api/security/authorize/{domain-id} – with query parameter of operation and target.
Example
Let’s start with a banking example where a bank-object can be account, general-ledger-report or ledger-posting-rules and account is further grouped into customer account or loan account, e.g.

Let’s assume there are five roles: Teller, Customer-Service-Representative (CSR), Account, AccountingManager and LoanOfficer, where
- A teller can modify customer deposit accounts.
- A customer service representative can create or delete customer deposit accounts.
- An accountant can create general ledger reports.
- An accounting manager can modify ledger-posting rules.
- A loan officer can create and modify loan accounts.
Creating a domain
The first thing is to create a security domain for your application. As we are dealing with banking domain, let’s call our domain “banking”.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/domains/banking" -d '{"id":"banking"}'
It will return response:
{"id":"banking","ownerSubjectNames":"super_admin"}
The first thing to note that we are passing user and password using Basic authentication as all accesses to administration APIs require login. Now, you can find out available domains via
curl -v --user "super_admin:changeme" "http://localhost:8080/api/security/domains"
which would return something like:
[{"id":"banking","ownerSubjectNames":"super_admin"},{"description":"default","id":"default","ownerSubjectNames":"super_admin"}]
Creating Users
Next step is to create users for the domain or application so let’s define accounts for tom, cassy, ali, mike and larry, i.e.,
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"tom","credentials":"pass"}'
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"cassy","credentials":"pass"}'
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"ali","credentials":"pass"}'
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"mike","credentials":"pass"}'
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"larry","credentials":"pass"}'
Note that each user is identified by an id or username and credentials and in above examples usernames or subject-ids are prefixed with domain-ids, e.g. “ddefault:super_admin”.
Creating Roles
As I mentioned, a role represents job title or responsibilities and each role can have one or more parents. By default, PlexRBAC defines an “anonymous” role, which is used for users who are not logged in and all user-defined roles extend “anonymous” role.

First, we create a role for bank employee called “Employee”:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Employee"}'
which returns
{"id":"Employee","parentIds":["anonymous"]}
As you can see the “Employee” role is created with parent of “anonymous”. Next, we create “Teller” role:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Teller","parentIds":["Employee"]}'
which returns:
{"id":"Teller","parentIds":["Employee"]}
Then we create a role for customer-service-representative called “CSR” that is extended by Teller e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"CSR","parentIds":["Teller"]}'
which returns:
{"id":"CSR","parentIds":["Teller"]}
Then we create a role for “Accountant”:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Accountant","parentIds":["Employee"]}'
which returns:
{"id":"Accountant","parentIds":["Employee"]}
Then we create a role for “AccountingManager”, which is extended by “Accountant”, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"AccountingManager","parentIds":["Accountant"]}'
which returns:
{"id":"AccountingManager","parentIds":["Accountant"]}
Finally, we create a role for “LoanOfficer”, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"LoanOfficer","parentIds":["Employee"]}'
which returns:
{"id":"LoanOfficer","parentIds":["Employee"]}
Creating Permissions
As described above, a permission is composed of operation, target and expression, where an operation and target can be any regular expression and expression can be any Javascript expression. However following permissions don’t define any expressions for simplicity. First, we create a permission to create or delete deposit-account, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(create|delete)","target":"DepositAccount","expression":""}'
which returns:
{"expression":"","id":"1","operation":"(create|delete)","target":"DepositAccount"}
Each permission is automatically assigned a unique numeric id. Next, we create a permission to read or modify deposit-account, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|modify)","target":"DepositAccount","expression":""}'
which returns:
{"expression":"","id":"2","operation":"(read|modify)","target":"DepositAccount"}
Then, we create a permission to create or delete loan-account
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(create|delete)","target":"LoanAccount","expression":""}'
which returns:
{"expression":"","id":"3","operation":"(create|delete)","target":"LoanAccount"}
Then we create a permission to read or modify loan-account, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|modify)","target":"LoanAccount","expression":""}'
which returns:
{"expression":"","id":"4","operation":"(read|modify)","target":"LoanAccount"}
Then we create a role to view and create general-ledger, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|create)","target":"GeneralLedger","expression":""}'
which returns:
{"expression":"","id":"5","operation":"(read|create)","target":"GeneralLedger"}
Finally, we create a permission for modifying posting rules of general-ledger, e.g.
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|create|modify|delete)","target":"GeneralLedgerPostingRules","expression":""}'
which returns:
{"expression":"","id":"6","operation":"(read|create|modify|delete)","target":"GeneralLedgerPostingRules"}
Mapping Permissions to Roles
Next task is to map permissions to roles. First we assign permission to view or modify customer deposit accounts to Teller role:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/Teller" -d 'permissionIds=["2"]'
which returns all permission-ids for given role, e.g.
["2"]
Then we assign permission to view, create, modify or delete customer deposit accounts to CSR (as CSR extends Teller it will automatically will get all permissions of Teller):
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/CSR" -d 'permissionIds=["1"]'
Then we assign permissions to create general ledger to Accountant:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/Accountant" -d 'permissionIds=["5"]'
Then we assign permission to modify ledger-posting rules to AccountingManager:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/AccountingManager" -d 'permissionIds=["6"]'
Mapping Users to Roles
A role is associated with one or more permissions and each user is assigned one or more role. First, we assign subject “tom” to Teller role:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/tom" -d 'rolenames=["Teller"]'
which returns list of all roles for given subject or user, e.g.
["Teller"]
Then we assign subject “cassy” to CSR role:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/cassy" -d 'rolenames=["CSR"]'
Next we assign subject “ali” to role of Accountant:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/ali" -d 'rolenames=["Accountant"]'
Then we assign role AccountingManager to “mike”:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/mike" -d 'rolenames=["AccountingManager"]'
Finally we assign subject “larry” to LoanOfficer role:
curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/larry" -d 'rolenames=["LoanOfficer"]'
Authorization
Now we are ready to validate authorization based on above security policies. For example, let’s check if user “tom” can view deposit-accounts, e.g.
curl -v --user "banking:tom:pass" "http://localhost:8080/api/authorize/banking?operation=read&target=DepositAccount"
On successful authorization, the API returns 200 http responose-code and on failure it returns 401 http response-code, e.g.
< HTTP/1.1 200 OK
Then we check if tom, the teller can delete deposit-account, e.g.
curl -v --user "banking:tom:pass" "http://localhost:8080/api/authorize/banking?operation=delete&target=DepositAccount"
which returns http-response-code 401, e.g.
< HTTP/1.1 401 Unauthorized
Then we create if cassy, the CSR can delete deposit-account, e.g.
curl -v --user "banking:cassy:pass" "http://localhost:8080/api/authorize/banking?operation=delete&target=DepositAccount"
which returns:
< HTTP/1.1 200 OK
Then we check if ali, the accountant can view general-ledger, e.g.
curl -v --user "banking:ali:pass" "http://localhost:8080/api/authorize/banking?operation=read&target=GeneralLedger"
which returns:
< HTTP/1.1 200 OK
Next we check if mike, the accounting-manager can create general-ledger, e.g.
curl -v --user "banking:mike:pass" "http://localhost:8080/api/authorize/banking?operation=create&target=GeneralLedger"
which returns:
< HTTP/1.1 200 OK
Then we check if larry, the loan officer can create posting-rules of general-ledger, e.g.
curl -v --user "banking:mike:pass" "http://localhost:8080/api/authorize/banking?operation=create&target=GeneralLedgerPostingRules"
which returns:
< HTTP/1.1 200 OK
Next, ali tries to create posting rules via
curl -v --user "banking:ali:pass" "http://localhost:8080/api/authorize/banking?operation=create&target=GeneralLedgerPostingRules"
which is denied:
< HTTP/1.1 401 Unauthorized
Summary
Above examples demonstrate how PlexRBAC can be used to define and enforce flexible security policies. In next post, I will describe instance based security, regular expressions and Java APIs for PlexRBAC.
Building Security Systems
December 27th, 2009
Being software developer for over eighteen years, I have observed a number of recurring problems and one of those recurring problems is security system. Most systems you build will require some kind of security so in this post I will go over core concepts when adding security to your system.
User Registration
A pre-requisite for any security system is to allow users to register to the system and store those users in some database, LDAP, Active Directory, or storage system. Though, for an internal application this step may be unnecessary.
Authentication
The authentication allows systems to validate users based on password or other form of verification. For internal applications within a company, users may have to use multiple applications with their own authentication and each external website would also require unique authentication. This quickly becomes burdensome for both users and applications as users have to remember the passwords and systems have to maintain them. Thus, many companies employ some form of Single-Sign-On and I have used many solutions such as SiteMinder, IChain, Kerberos, Open SSO, Central Authentication Service (CAS), or other home built solutions. These Single-Sign-On systems use reverse proxy servers that sit in front of the application and intercepts all requests and automatically redirects users to login page if the users are not authenticated. When an internal system consists of multiple tiers such as services, it is often required to pass authentication tokens to those services. In J2EE systems, you can Common Secure Interoperability (CSIv2) protocol to pass the authentication to other tiers, which uses Security Attribute Service (SAS) protocol to perform client authentication and impersonation.
For external systems, Open ID is a way to go and I have used RPX to integrate Open ID for a number of sites I have developed such as http://wazil.com/, http://dealredhot.com/, etc.
There are a number of factors that make authentication a bit tricky such as when part of your system does not require authentication, you have to ensure the authentication policy is being used correctly. Also, in general authentication requires https instead of http, so you have to ensure that the site use those protocols consistently. In generaly, static contents such as css, javascript and images do not require authentication but often they are also put behind authentication by mistake.
Another factor related to authentication is session management. A session determines how long the user can access the system without login. Though, many systems provide remember-me feature, but often sessions require system resources on the server. It’s essential to keep the session short as it can effect scalability if it’s stored on the server. I generally prefer keeping the session very short and storing only user-id and a couple of other database-ids such as shopping-cart-id, request-id, etc. If they are short, they can also be stored in cookies that makes a stateless system so you can scale easily.
Authorization
Not all users are same in most systems, thus authorization allows you to provide access control to limit the usage based on permissions and access control. There are a number of ways to define authorization such as Access control list, Role-based access control, Capability-based security, etc. In most systems, I have used J2EE/EJB Security, Java Web Security, JAAS, Acegi, which is now part of Spring and home built systems. As security is a cross cutting concern, I prefer to define those declaratively in a common security file or with annotations. There is nothing worse than sporadic security code mixed with your business logic.
One of feature I have found lacked in most of open source and commercial tools is support for instance based security or dynamic security that verifies runtime properties. For example, in most RBAC systems you can define rule that a purchase order can be approved by a role “POApprover”, but it does not allow you to say that “POApprover” can only approve if the user is from the same department or if amount is less than $10,000, etc.
UI or Resource Protection
When users have various level of access, it is essential to hide the UI elements and resources that are not accessible. Though, I have seen some systems employ security by obscurity that only hide the resources without actually enforcing the permissions, but it’s a bad idea. This can be complicated when the access level is very fine grained such as when a single form has fields based on role and permissions.
Database Security
The security must be enforced in depth, ranging from the UI, business and database tier. The database operations must use security to prevent access to unauthorized data. For example, let’s assume a user can post and edit blogs, it is essential that the database only allows the user to modify his/her blog. Also, it is critical that any kind of sensitive data such as passwords or personal identification with encryption. This is another reason I like OpenId or SSO solution because you don’t need to maintain them.
Method/Message Security
The message security ensures that a user only invokes the operations that he/she is authorized. For example, Acegi provides an annotation based mechanism to protect unauthorized methods.
Data Integrity
Any communication based systems may need to use message authentication check (MAC) to detect changes to the data.
Confidentiality
Any communication based systems may need to encrypt sensitive data with HTTPS.
Non-repudiation
The system must audit users action so that they cannot repudiate them.
Summary
As achieving high level of security can be difficult and expensive so you need to treat security as a risk and employ the level of security that suits the underlying system. Finally, as I have found most RBAC systems lack, I have started my own open source project PlexRBAC to provide instance based security. Of course if you hare interested in assisting with the effort, you are welcome to join the project.
Dynamic Inheritance and Composition
December 13th, 2009
Static Inheritance
Inheritance is a core feature of object oriented languages that has been used to simulate real world by modeling closely related objects and to build reusable code. The inheritance relationship is defined statically in class specifications and it comes in various flavors such as:
Single Inheritance
It allows a class to be extended by just one other class.
Multiple Inheritance
It allows a class to be derived from multiple classes and historically has been difficult to maintain and has been source of diamond inheritance in C++, though other languages use order such as Method Resolution Order (MRO) in Python to avoid those issues.
Interfaces
The interfaces are used in C# and Java to define methods without implementation and a class can implement multiple interfaces without the downsides of multiple inheritance.
Mixins
The mixins are available in Ruby and D, that use mixins for code reuse. The mixins are similar to interfaces with implementations except they aggregate methods and attributes at runtime.
Traits
The traits are available in Squeak and Scala and are conceptually similar to Mixins except traits do not allow attributes.
Dynamic Inheritance
As opposed to static inheritance, dynamic inheritance can be added at runtime using Object Extension Pattern, which I first learned in Erich Gamma, et al’s Gof patterns. In late 90s, I used Voyager ORB for building distributed systems, which used this pattern. Following example shows how this pattern can be used:
Let’s define a marker interface Extension in Java such as:
1 package ext; 2 3 public interface Extension { 4 5 } 6 7






