the documentation suggest ACL can control access to a property in resource:
" Simple rules are used to control access to a namespace, asset or property of an asset"
but I can't find any info on how to define ACL rules to control a property of resource. would appreicate if anyone can advise or point me to documentations. thanks in advance!
Property level access control has not yet been implemented and is hence not yet supported.
Here is my understanding of this, if you read further into that the ACL Documentation you can see that you when a participant tries to access an asset, the rules can check the properties of the asset to determine whether or not that participant is the owner of that asset.
Quoted from the documentation:
The rule below states that any instance of the org.example.SampleParticipant type can perform ALL operations on all instances of org.example.SampleAsset IF the participant is the owner of the asset.
rule SampleConditionalRule {
description: "Description of the ACL rule"
participant(m): "org.example.SampleParticipant"
operation: ALL
resource(v): "org.example.SampleAsset"
condition: (v.owner.getIdentifier() == m.getIdentifier())
action: ALLOW
}
The rule below states that any instance of the org.example.SampleParticipant type can perform ALL operations on all instances of org.example.SampleAsset IF the participant is the owner of the asset AND the participant submitted a transaction of the org.example.SampleTransaction type to perform the operation.
rule SampleConditionalRuleWithTransaction {
description: "Description of the ACL rule"
participant(m): "org.example.SampleParticipant"
operation: READ, CREATE, UPDATE
resource(v): "org.example.SampleAsset"
transaction(tx): "org.example.SampleTransaction"
condition: (v.owner.getIdentifier() == m.getIdentifier())
action: ALLOW
}
Related
Let's assume we have the following "Create User" scenario:
Users can signup to the application using Facebook, Google+ or LinkedIn;
The backend should retrieve some basic profile information in order to register the user(email, firstName and lastName);
Users are registered with a "client Id" (Just adding complexity to the business rule);
When a signup process is done the data should be sent to a notification topic.
I can imagine a create user request with the following structure:
{
"clientId": "someClientId",
"authProvider": "FACEBOOK | GOOGLE | LINKEDIN",
"accessToken": "someAccessToken"
}
So, thinking about the registration/validation flow we would have:
Check if the create user request is valid;
Check if the clientId is valid;
Try to retrieve the profile information from the social network api;
Check if all the required profile information is filled;
Check if the user exists in the database;
Register the user;
Send the data to the notification topic;
Pass the data to the presenter.
Jumping straight to the use case, we would have a constructor like:
CreateUserUseCase(
ApplicationClientGateway applicationClientGateway,
SocialNetworkGateway socialNetworkGateway,
UserGateway userGateway,
NotificationGateway notificationGateway,
Presenter presenter
)
and an execute method:
execute(CreateUserRequest request)
// validates the payload
// something like
if (request == null)
presenter.setError(someError);
// validates the clientId
applicationClientGateway.findById(request.getClientId())
// retrieves the profile information
// how to inject dinamically the implementation for
// Facebook, Google or LinkeIn based on a request parameter?
profile = socialNetworkGateway.findByAccessToken(request.getAccessToken());
// checks if the user exists
userGateway.findByEmailAndAuthProvider(profile.getEmail(), request.getAuthProvider());
//register the user
userGateway.insert(user);
//sends the notification
notificationGateway.send(user);
// sets the result
presenter.setResult(user);
Now, we have a constructor with lots of arguments(code smells?) and at least 5 validation steps in the execute method.
It looks like a violation of the SRP, so, how can we decompose this code in order to reduce complexity in the interactor?
First of all, lets break this in some small steps:
1) Related to the presenter, looks like you are intersted in give the workflow some output, right? Assuming that, maybe it will be better to return what you want from the usecase and handle this one layer above. (-1 parameter at constructor)
2) Like the others answers are saying, looks like your usecase has a LOT of responsabilities right now. I will suggest you to break this in more then one usecase.
Something like:
... Your first gateway (API)
..... ValidateClientId.execute();
..... profile = RetrieveProfile.execute();
..... InsertUser.execute(...)
3.1) Related to inject the correct bean based on the correct social network, you can handle this logic INSIDE the gateway, not before call it. Remembet that one gateway CAN call another gateway (they are at same layer). So, I suggest you to use something like.
At usercase -> socialNetworkGateway.findByAccessToken(...)
Inside the gateway you can do your "switch" and call somthing like the FacebookGateway, GoogleGateway, etc.
SRP does not say that you have to have small methods or only few constructor parameters. SRP says "there should be only a single reason to change the code".
As far as I can see you explicitly implemented the "business logic sequence" required to register a new user. Even though this may require some "external services" and/or repositories there is still only one reason to change the logic of this code: if the logic "how to register a user" changes.
From this perspective you are not violating SRP.
According to Uncle Bobs picture on "control flow" (https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) it is also totally correct to pass the presenter.
If you still feel the need to reduce the dependencies of your use case class I would suggest looking into "unit of work" pattern and check whether it would make sense to combine some of the dependencies.
More details on "What is a use case in Clean Architecture" you can find in my blog series: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases/
I went through the latest documentation of search guard, https://docs.search-guard.com/latest/roles-permissions and could only find a short explaination for single permissions:
Single permissions either start with cluster: or indices:, followed by
a REST-style path that further defines the exact action the permission
grants access to.
So one permission could be on cluster level or on indices level.
indices:data/read/search
So the part before : could be indices or cluster, but I'm not clear how to understand the parts after semicolon, and what are these parts seperated by "/".
Can someone please explaine me more about this or point me to some documentation, which I maybe missed?
Thanks
Dingjun
This is actually not related to Search Guard but to Elasticsearch. When you interact with Elasticsearch, e.g. indexing data or searching data, what you are really doing is executing actions. Each action has a name, and this name is in the format you outlined.
For example, have a look at org.elasticsearch.action.search.SearchAction:
public class SearchAction extends Action<SearchRequest, SearchResponse, SearchRequestBuilder> {
public static final SearchAction INSTANCE = new SearchAction();
public static final String NAME = "indices:data/read/search";
private SearchAction() {
super(NAME);
}
...
}
The permission schema of Search Guard is based on these Elasticsearch action names. So the naming conventions is actually an Elasticsearch naming convention.
Elastic does not publish a list of these action names anymore. AFAIK in X-Pack Security you cannot actually go down to this level of detail regarding permissions, that's probably why they stopped to do so.
The Search Guard Kibana plugin comes with a list of permissions you might use as a guideline:
https://github.com/floragunncom/search-guard-kibana-plugin/blob/6.x/public/apps/configuration/permissions/indexpermissions.js
https://github.com/floragunncom/search-guard-kibana-plugin/blob/6.x/public/apps/configuration/permissions/clusterpermissions.js
The question is if you really need to implement security on such a fine-grained level. That's what the action groups are for. These are pre-defined sets of permissions and should cover most use cases. Also, they are updated with each release if the permissions in Elasticsearch change, so it's safer to use action groups than to rely on single permissions. But as always, it depends on the use case.
I'm using laravel gates in my web.php, where i add middleware for can as follows
Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth')->middleware('can:admin');
i want to add another rule for example can:admin or can:moderator so either of them is true, gate will allow
any ideas ?
I don't think you can use a logical or operator when enabling middleware for a route.
You could make a third Gate, that returns true when the user is either admin or moderator.
Another option is that you would create a ProductPolicy. In this policy you could create a sellProduct() method that checks if the user has the right roles:
public function sellProduct(User $user, Product $product)
{
// Return true when user is moderator or admin
}
You would have to call this method in your ProductController#Sell with:
$this->authorize('sellProduct', $product);
Take attention that gates and policies are meant to determine if a user is authorized to perform an action. This can be done by checking if the user has a certain role, or if the user is the owner of, in your case, a product. When you define a Gate as 'admin' things could get mixed up.
Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth, can:admin');
what does this means ?
#PreAuthorize("hasPermission('DEVICE', {'DELETE','CREATE'})")
whether it checks Device object has DELETE AND CREATE both permission or any one of it?
As said in comment, it depends on which PermissionEvaluator you have. If you use the built-in ACL system, this will delegate to DefaultPermissionGrantingStrategy. The javadoc says:
The method will iterate through each of the permissions in the order specified. For each iteration, all of the sids will be considered, again in the order they are presented. A search will then be performed for the first AccessControlEntry object that directly matches that permission:sid combination. When the first full match is found, the grant or deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return true. If the ACE specifies to deny access, the loop will stop and the next permission iteration will be performed.
(sids = security identities, the user's principal and authorities)
In practice this means only one of the permissions is required for the method to return true.
I'm trying to define the type of entered credentials with:
SID_NAME_USE pe;
...
resolved=LookupAccountNameW (NULL,L"builtin\users",&sid,&cbsid,buff,&dd,&pe);
No matter if I enter "builtin\users" or "users" it resolves successfully but returns SidTypeAlias in pe enum.
But I expect SidTypeWellKnownGroup or SidTypeGroup.
Question: How to reliably define if given string is a Windows Group name ?
The MSDN page Well-known SIDs briefly describes the meaning of "alias" in this context:
The following table has examples of domain-relative RIDs that you can use to form well-known SIDs for local groups (aliases).
One of the table entries is for the Users group, so the behaviour you are describing is as expected.
You can continue to use LookupAccountName() as you planned, you simply need to modify your code to recognize that any of SidTypeAlias, SidTypeWellKnownGroup, or SidTypeGroup represent groups.
The Glossary of the Security Account Manager Remote Protocol specification gives some hints as to what SidTypeAlias might be:
alias object: See resource group.
resource group: A group object whose membership is added to the authorization context only if the server receiving the context is a member of the same domain as the resource group.
This suggests that "alias" means "Domain Local group" in this context.
I confirmed this in my domain, by obtaining all domain groups using DirectorySearcher and calling LookupAccountName on each. Results:
all Global and Universal groups had SidTypeGroup;
all non-builtin Domain Local groups (groupType 0x80000004) had SidTypeAlias;
builtin Domain Local groups (those with groupType 0x80000005 = system-created domain local, such as Account Operators or Users) also had SidTypeAlias, but I had to run the code on a DC - when executed on a member workstation, LookupAccountName failed (ERROR_NONE_MAPPED) for all such groups except IIS_IUSRS.
Bottom line - SidTypeAlias should be treated as a group.