Which access control system is right for dynamic multi layer security check? - permissions

I have RESTful APIs and in microservice architecture. Such as -
Auth service
User service
Product service
More ...
Currently, I am validating request via JWT token which can be obtained from Auth service. Now, time has come to implement an access control system.
It's an internal tool application (pretty complex) and my primary thought was to use RBAC (Role-based access control) but the application isn't traditional. In application, User A can pair up with another User B and once pair up completed, based on User B's settings User A can perform various action.
So permissions aren't static and they're based on other variables. So should I go for ABAC/PBAC system? Any suggestions?
Thoughts on ABAC
Subjects - Who is sending request e.g User A
Object - Accessing what? e.g Module A
Actions - Read or write? e.g Read GET request
Environment - condition e.g for which User? (User B)

My biased answer is: yes you should :-) (I work for Axiomatics and all we do is PBAC/ABAC and have done so for 15 years).
Note that PBAC and ABAC in this context are the same. PBAC is actually a much older concept. We've been using policies in many places e.g. network access control or SDDL in the past.
The main benefit of attribute-based access control for you (abac) is that it will give you the freedom to adapt your access control policies over time without having to rewrite your application. Effectively, you decouple / externalize authorization from the application.
The following shows the basic architectural flow in ABAC whereby a component (the PEP) intercepts the business flow and converts it into an authorization flow (Can Alice view record 123?).
Policies can be written in xacml or alfa. I prefer the latter since its syntax is super lightweight (read more on Wikipedia).
For instance you could write:
namespace com.acme{
/**
* Tutorial 101 - a flat approach using 4 rules
*/
policyset recordsAccess{
apply firstApplicable
/**
* Records access control
*/
policy records{
target clause object.objectType == "record"
apply firstApplicable
/**
* R1 - A manager can view any records
*/
rule managersView{
target clause user.role == "manager" and action.actionId == "view"
permit
}
/**
* R2 - An employee can view a record in their own department
*/
rule employeesView{
target clause user.role == "employee" and action.actionId == "view"
condition user.department == record.department
permit
}
/**
* R3 - An employee can edit a record they own, if it is in draft mode
*/
rule employeeEdit{
target clause user.role == "employee" and action.actionId == "edit" and record.status == "draft"
condition com.acme.record.owner == com.acme.user.employeeId
permit
}
/**
* R4 - A manager can publish a record if the record is in final
* mode and it belongs to a employee below that manager.
*/
rule managerPublish{
target clause user.role == "manager" and action.actionId == "publish"
condition stringIsIn(stringOneAndOnly(com.acme.record.owner),com.acme.user.subordinate)
permit
}
}
}
}

Related

What if access control rule defined for participant/asset contradicts access control rule for transaction?

I have a question regarding access control.
Specifically, the question is about the relationship between access control rules defined for participants or assets on the one hand and asset control rules defined for transactions accessing those participants/assets.
Here is an example:
Assume a Hyperledger Fabric network is used to create some kind of social network for employees of a company.
The following rule states that an employee has write access to his own data:
rule EmployeesHaveWriteAccessToTheirOwnData {
description: "Allow employees write access to their own data"
participant(p): "org.company.biznet.Employee"
operation: UPDATE
resource(r): "org.company.biznet.Employee"
condition: (p.getIdentifier() == r.getIdentifier())
action: ALLOW
}
Let's assume that the write access is facilitated through a transaction called "UpdateTransaction". Further assume that (maybe by accident) the action value of the access control rule of transaction "UpdateTransaction" is set to "Denied"
rule EmployeeCanSubmitTransactionsToUpdateData {
description: "Allow employees to update their data"
participant: "org.company.biznet.Employee"
operation: CREATE
resource: "org.company.biznet.UpdateTransaction"
action: Denied
}
Now there is the following situation:
Each employee is (through rule 1) given the right to change his/her data.
At the same time employees are not allowed to submit the transaction "UpdateTransaction" to change the data (see rule 2).
Is it now impossible for employees to change their data? Or are employees still able to change their data without submitting the transaction "UpdateTransaction"?
Put differently: is there a way for participants to access data (for which they have access rights) without using any of the transactions defined in the .cto-file?
I think the answer is, it depends.
In your example, denying access to the org.company.biznet.UpdateTransaction transaction would result in org.company.biznet.Employee participants being unable to use that transaction to update their data, even though they would otherwise be allowed.
Having said that, you should keep the system transactions in mind since they provide another potential route for org.company.biznet.Employee participants to update their own data.
For example, I tried that out on the basic-sample-network by replacing the EverybodyCanSubmitTransactions rule with
rule NobodyCanSubmitTransactions {
description: "Do not allow all participants to submit transactions"
participant: "org.example.basic.SampleParticipant"
operation: CREATE
resource: "org.example.basic.SampleTransaction"
action: DENY
}
That business network includes an OwnerHasFullAccessToTheirAssets rule and I was able to use the org.hyperledger.composer.system.UpdateAsset transaction to make updates for participants that owned an asset using the command,
composer transaction submit -d "$(cat txn.json)" -c party1#basic-sample-network
Where txn.json contained,
{
"$class": "org.hyperledger.composer.system.UpdateAsset",
"resources": [
{
"$class": "org.example.basic.SampleAsset",
"assetId": "ASSET1",
"owner": "resource:org.example.basic.SampleParticipant#PARTY1",
"value": "5000"
}
],
"targetRegistry": "resource:org.hyperledger.composer.system.AssetRegistry#org.example.basic.SampleAsset"
}
That wouldn't work if you had locked down the system namespace in your ACL rules though. (ACLs need a lot of thought!)
The other important thing to remember about ACLs is that they do not apply if you use the getNativeAPI method to access data via the Hyperledger Fabric APIs in your transaction processor functions.
Check out the system namespace reference along with the ACL reference, plus there is an ACL tutorial which may be of interest if you haven't seen it.

Is There A Generic Way To Search For LDAP Groups With Shiro?

I am using org.apache.shiro.realm.ldap.DefaultLdapRealm to authenticate against LDAP (using ldap://ldap.forumsys.com:389/dc=example,dc=com as an example).
However, when I try to check for Roles it always fails. It turns out that the DefaultLdapRealm returns null when searching for groups.
/**
* Method that should be implemented by subclasses to build an
* {#link AuthorizationInfo} object by querying the LDAP context for the
* specified principal.</p>
*
* #param principals the principals of the Subject whose AuthenticationInfo should be queried from the LDAP server.
* #param ldapContextFactory factory used to retrieve LDAP connections.
* #return an {#link AuthorizationInfo} instance containing information retrieved from the LDAP server.
* #throws NamingException if any LDAP errors occur during the search.
*/
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals,
LdapContextFactory ldapContextFactory) throws NamingException {
return null;
}
There is a similar question from 2012, however, it looks like a copy of the code from the ActiveDirectoryRealm.
Does everyone who wants to use LDAP with groups using Shiro have to write a custom Realm?
Couldn't the DefaultLdapRealm take a property that configures the search filter for groups but doesn't require extra code (like the userDNTemplate is used for login)?
Does such a Realm already exist in a maven dependency?
I think the biggest issue is there are many many different ways to store things in LDAP, there is a hand full of common techniques though.
op moved this to a mailing list thread: http://shiro-user.582556.n2.nabble.com/New-LDAP-Realm-Proposal-tp7581200p7581291.html

ADFS - Issuance Authorization Ruleset error

In our system, we have users registered from different domain (lets say their mail address are #gmail.com,#outlook.com,#yahoo.com). I have a requirement to restrict the user's access to RP based on the domain he comes from. For this setup, I tried to configure Issuance Authorization rule in ADFS (to allow users only from a particular domain) with the below rule
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", Value =~ "gmail.com$"]
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");
I was passing email address claim through issuance authorization rule tab so I didn't initialized the input in the authorization ruleset as mentioned in the technet link (under Sending the execution output to the claims pipeline Section)
After the entire process has run for a give rule set (steps 1, 2, and 3), the newly issued outgoing claims (content of the output claim set) will be used as input to the next rule set in the claims pipeline. This allows for claims to flow from the output of one rule set to the input for another rule set, as shown in the following illustration.
But the authorization doesn't seem to work.
The claims configured in the first tab ( Issuance transform rules ) are not passed to the second tab (Issuance Authorization rules).
So we need to repeat the process again in the second tab (map emailaddresses -> emailaddress) as shown below.
Now the custom rule works perfectly.
If you need to add few more email domains to the acceptance criteria just use the "|" symbol:
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", Value =~ "yahoo.com$|gmail.com$"]
=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");

Adding more user information to ASP.NET Default Membership Provider

My application is an MVC4 application with a Domain Model created in EF 5 Code First. The application requires Authentication / Authorization, and I want to use the default ASP.NET Membership Provider.
With this in mind, I have gone ahead and used the aspnet_reqsql utility to add all the tables necessary for the ASP.NET Default Membership provider.
However, my application needs to store more information about the User than what is provided by default by the Membership provider. For example:
First Name
Last Name
Date of Birth
Address (split into different
columns)
These things are not present in the membership provider tables. So I went ahead and added all the missing columns to the users table, and also created an Addresses table, and created a relationship between the User and the Address.
I then went into my Registration View Model, and added the missing data fields, I then went into the AccountController and checked the method that gets called to register a user. It is this:
//
// Summary:
// Creates a new user profile entry and a new membership account.
//
// Parameters:
// userName:
// The user name.
//
// password:
// The password for the user.
//
// propertyValues:
// (Optional) A dictionary that contains additional user attributes. The default
// is null.
//
// requireConfirmationToken:
// (Optional) true to specify that the user account must be confirmed; otherwise,
// false. The default is false.
//
// Returns:
// A token that can be sent to the user to confirm the user account.
//
// Exceptions:
// System.InvalidOperationException:
// The WebMatrix.WebData.SimpleMembershipProvider.Initialize(System.String,System.Collections.Specialized.NameValueCollection)
// method was not called.-or-The Overload:WebMatrix.WebData.WebSecurity.InitializeDatabaseConnection
// method was not called.-or-The WebMatrix.WebData.SimpleMembershipProvider
// membership provider is not registered in the configuration of your site.
// For more information, contact your site's system administrator.
public static string CreateUserAndAccount(string userName, string password, object propertyValues = null, bool requireConfirmationToken = false);
This method is confusing me a lot ! I was expecting to see the logic of data insertion into the database, so that I may edit it and add make the method take care of my newly added fields too, but all that missing!
What am I missing? How can I achieve the type of registration that I want?
First of all, you want to use new ASP.NET Universal Providers which uses Entity Framework.
If you want to add custom columns, create a new table like the following, and retrieves that custom data based on UserId by yourself.
Note: You cannot alter (add/remove) columns of any table created by Membership Provider, if you want to use DefaultMembershipProvider.
In other words, if you start adding columns, you'll have to implement CustomMembersipProvider. I do not recommend it if you are new to MembershipProvider.

data realted access in authenciation

I am build a web application,and there are some operations is protected for identified people.
I use the sping security for access control,however I have no idea how to control them when deep to the data level.
For exmaple,there are two operation list and edit operation.
Both the administrator of the company and the administrator of one department can access these operations,but the data they can 'list' or 'edit' are not the same.
administrator of the company can get access to all the data of the company while administrator of one department can only get access to the data of his/her department.
So I wonder what is the best practice to implement these requirements?
Most easy method - use PostFilter annotation on service layer.
#Transactional(readonly=true)
#PostFilter("hasPermission(filterObject, 'edit')")
List<DepartamentData> getDepartamenData();
#Transactional
#PreAuthorize("hasPermission(#data, 'edit')")
List<DepartamentData> editDepartamenData(DepartamentData data);
Or another example:
#Transactional(readonly=true)
#PostFilter(
" hasRole('company_admin')" +
"|| (hasRole('departament_admin') && filterObject.departament.equals(principal.departament))")
List<DepartamentData> getDepartamenData();