We want to be able to store attributes/constraints in fortress so that we can
do fine grained security checks. We would like to get thoughts/feedback on this
proposal. Our goal is to store permission attributes and role constraints based
on those attribute in fortress, but not necessarily have fortress make the
decision. In our applications, we pull back the list of roles and permissions
when the user logs in, not on every security check, so we would have the
application interpret the constraints. That being said, here is the proposal...
1. Add a new ldap attribute type (ftPA) to store 0 to many attributes about a
permission and other metadata about the attribute (required, valid values,
etc...). It would be up to each application to define it's permissions and any
attributes that are relevant to each permission. In this example, we have an
account.withdraw permission that needs constraints for the account id and a
withdraw limit for each user.
Permission: account.withdraw
- ftPA:
AccountId?dataType=int&required=true&validValues=SELF,ANY,int&comparator=equals&default=SELF
- ftPA: WithdrawLimit?dataType=int&comparator=max
2. Role creation and permission assignment would stay the same.
3. When a user is assigned to a role that has a permission with a ftPA, we
would allow adding of role constraints to the user-role assignment. In this
example, we are changing ftRC so that it can specify a type of constraint
(temporal or filter). There could be many "filter" ftRC entries if the ftPA
were different. We may also want to add a "seq" to allow grouping ftRCs
together.
User: chris
- ftRA: BANK_USER
- ftRC:
BANK_USER$seq$0$type$temporal$role1$0$1000$0000$none$none$none$none$all
- ftRC: BANK_USER$seq$0type$filter$AccountId=12345&WithdrawLimit=500
4. When getting roles or session permissions for a user, the additional
constraints would need to be returned.
{
"objName": "account",
"opName": "withdraw",
"constraints": [ "AccountId=12345&WithdrawLimit=500" ]
}
5. Once our application had the list of permissions and constraints, it would
then do it's own checks, potentially something like...
@PermissionRequired("account.withdraw") //coarse grained check
public void withdraw(Account account, float amount){
Map map = new HashMap();
map.put("WithdrawLimit", amount);
map.put("AccountId", account.getId());
doesUserHavePermission("account.withdraw", map); //fine grained check
}