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.
Related
This is my Schema.
Query {
me: User #isAuthenticated
}
When I add #isAuthenticated it is handled on server side but in GraphQL Playground the directive doesn't show. I have some role based access system and I want to show all the role directives publicly so that API user can understand what role is wanted for which query.
Schema directives can be used to transform the schema or add functionality to it, but they cannot be used to expose any sort of metadata to the client. There's ongoing discussion here with regards to how to implement that sort of functionality. For the time being, your best bet would be to utilize descriptions.
"""
**Required roles**: `ADMIN`
"""
Query {
me: User #isAuthenticated
}
tldr: Can I securely pass a raw query string (retrieved as a URL parameter) into a Lucene QueryParser without any added input sanitization?
I'm not a security expert, but I need some advice. As the title states, is it safe to use this controller method:
#CrossOrigin(origins = "${allowed-origin}")
#GetMapping(value = "/search/{query_string}", produces = MediaType.APPLICATION_JSON_VALUE)
public List doSearch(#PathVariable("query_string") String queryString) {
return searchQueryHandlerService.doSearch(queryString);
}
In tandem with this service method (the error handling is for testing only):
public List doSearch(String queryString) {
LOGGER.debug("Parsing query string: " + queryString);
try {
Query q = new QueryParser(null, standardAnalyzer).parse(queryString);
FullTextEntityManager manager = Search.getFullTextEntityManager(entityManager);
FullTextQuery fullTextQuery = manager.createFullTextQuery(q, Poem.class, Book.class, Section.class);
return fullTextQuery.getResultList();
} catch (ParseException e) {
LOGGER.error(e);
return Collections.emptyList();
}
}
With only basic input sanitization? If this isn't safe are there measures I can take to make it safe?
Any help is greatly appreciated.
I've been looking into this on and off for the last few weeks and I cannot find any reason why it wouldn't be safe, but It's such an obscure question (in an area I'm unfamiliar with) that I may be missing some obvious, fundamental problem anyone working in the area would see immediately.
A FullTextQuery is always read only, so you don't have to be concerned with people dropping tables or similar issues that you might have to consider when dealing with SQL injection.
But you might want to be careful if you have security restrictions on what data can be seen by your users.
The API also restricts the operation to a certain set of indexes - in your case those containing the Poem entities - so it's also not possible to break out of the chosen indexes.
But you need to consider:
is it ok if the user is able to somehow find a different Poem than what you expected them to look for
if you share the same index with other entities, there might be some ways to infer data about these other entities
So to be security conscious you might want to:
each entity type gets indexed into its own index (which is the default).
enable some FullTextFilter to restrict the user query based on your custom rules.
actually check the content of each result before rendering it, so to remove content that your other filters didn't catch.
If you are extremely paranoid, consider that any full-text index can actually reveal a bit about how frequent certain terms are in the whole index. People are normally not too concerned about this as it's extremely hard to take advantage of, and only minimal clues about the data distribution are revealed.
So back at your example, if this index just contains poems and you're ok with allowing any user to see any poem you have stored, giving away clues about which poems you are making available is normally not a security concern but is rather the whole point of your service.
Just like as title, I want to ask what difference between
fromPin()
and
fromLocalDatastore()
By the way, Pin and datastore two terminologies. What difference between two of them ?
Thanks.
There is a slight difference and you can see it from the docs and from the decompiled code of the Parse library (okay, this last one is more complicated...).
The docs says:
fromLocalDatastore(): Change the source of this query to all pinned objects.
fromPin(): Change the source of this query to the default group of pinned objects.
Here you can see that, interally on Parse, there is a way to get all the objects from the entire set of pinned data, without filters, but also from a so-called "default group". This group is defined in the Parse code with the following string: _default (o'rly?).
When you pin something using pinInBackground, you can do it in different ways:
pinInBackground() [without arguments]: Stores the object and every object it points to in the local datastore.
This is what the docs say, but if you look at the code you'll discover that the pin will be actually performed to the... _default group!
public Task<Void> pinInBackground() {
return pinAllInBackground("_default", Arrays.asList(new ParseObject[] { this }));
}
On the other hand, you can always call pinInBackground(String group) to specify a precise group.
Conclusion: every time you pin an object, it's guaranteed to be pinned to a certain group. The group is "_default" if you don't specify anything in the parameters. If you pin an object to your custom group "G", then a query using fromPin() will not find it! Because you didn't put it on "_default", but "G".
Instead, using fromLocalDatastore(), the query is guaranteed to find your object because it will search into "_default", "G" and so on.
I have to implement access controls in my application and I am using spring ACLs for it. My model has User, groups, permissions.
The problem I am trying to solve is to get permissions on a domain object for a user. I was able to get all the access control entries for that user (principal sid, and group sids), and using that I was able to get a final set of permissions by taking a union over all the permissions. Lets say the combined mask is 111, which would be Read, Write, and Create permissions going by the permissions defined in BasePermissions.
The problem I am facing now is I cant find any way to get a list of all defined base permissions so that I can compare the mask to individual permissions. The base permission class does not seem to provide any such method. I do not want to hardcode cases in an if-then clause, since the number of permissions might increase in future.
Any pointers would be appreciated. Thanks.
You can check for the permission by using the AclPermissionEvaluator by passing an array of Permission instances to hasPermission method as a parameter. Check the source in the given link for implementation.
#Autowired
private PermissionEvaluator permissionEvaluator ;
........
Object permission = new Permission[]{permissionFactory.buildFromName("READ"),permissionFactory.buildFromName("WRITE"), permissionFactory.buildFromName("CREATE")};
permissionEvaluator.hasPermission(authentication, oid, permission);
And as mentioned in this answer do not forget to register the AclPermissionEvaluator in your spring context.
UPDATE: To get all the permission that a user has on a domain object --
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
.......
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(oid, sids);
List<AccessControlEntry> aces = acl.getEntries();
List<String> permissionsList = new ArrayList<String>();
for (AccessControlEntry ace : aces ) {
permissionsList.add(ace.getPermission().getPattern());
}
As #Ravi said: use the method readAclById from the class JdbcAclService will not work if you use the BasicLookupStrategy.class. Becasuse the LookupStrategy.readAclsById (ignored the second paramter sids). I suggest you write your custom lookupstragey.
What you are trying to do is check if a CumulativePermission has a specific permission. You can do it using this method:
public static boolean containsPermission(Permission cumulativePermission, Permission singlePermission) {
return (cumulativePermission.getMask() & singlePermission.getMask()) == singlePermission.getMask();
}
I'm writing some C++/Win32 code to search for a user in an LDAP directory (really I need to validate a username/password is correct, and then verify group membership). I have the username, so I'm hoping something like the following will work:
(&(objectCategory=person)(objectClass=user)(uid={username}))
When I call ldap_search with this search/filter, I have to provide a starting base (node/OU/whatever) to search. But I don't know where to start the search -- all I have is the username. Is there anyway to specify the root of the tree that will work with OpenLDAP, Active Directory, Netscape LDAP, etc, etc?
Also, anyone that can answer that could probably help with this: Is the uid attribute universally supported, or do I need to search on a different attribute depending on what brand of LDAP server I'm talking to? (I've seen references to people needing to search on uid, CN and even SAMAccountName).
Regarding your first question about generically retrieving a search base:
Every LDAP directory server (conforming to the LDAP protocol I think) exposes some operational thingies under a node called RootDSE. One of the things you can retrieve through RootDSE are the namingContexts which essentially can tell you what the different trees are hosted on this server.
So you can retrieve a top-level search base for your username-search. Please be aware: some LDAP (OpenLDAP for example) servers can host multiple trees so you have to come up with a solution when multiple naming contexts are found.
The RootDSE can be retrieved by querying the server for the DN "" (empty string) and specifiyng that you want to get all the operational attributes as well. Just some example for an OpenLDAP server:
ldapsearch -H ldap://ldap.mydomain.com -x -s base -b "" +
# note the + returns operational attributes
This should return something similar to that shown below (from OpenLDAP 2.4.8) - the values in parentheses are added explanations and are not returned by the server:
dn:
structuralObjectClass: OpenLDAProotDSE
configContext: cn=config
namingContexts: dc=example,dc=com
namingContexts: dc=example,dc=net
monitorContext: cn=Monitor
supportedControl: 1.3.6.1.4.1.4203.1.9.1.1 (Contentsync RFC 4530)
[...]
supportedExtension: 1.3.6.1.4.1.4203.1.11.1 (ModifyPassword RFC3088)
[...]
supportedFeatures: 1.3.6.1.1.14 (Modify-Increment RFC4525)
[...]
supportedLDAPVersion: 3
supportedSASLMechanisms: NTLM
[...]
entryDN:
subschemaSubentry: cn=Subschema
(from http://www.zytrax.com/books/ldap/ch3/#operational)
Regarding your second question about the availability of the uid attribute:
I don't think that you should rely on this one as it strongly depends on the schema used for storing user data (although most user-schema-classes will have a uid attribute I think). But that depends on the flexibility you want to put into your program. Perhaps the best way would be to make the user-filter-string configurable by the end-user (you could even do this with the search base which would have some performance advantages (no need to search the whole tree when users are only located in a small subtree and no need to query the RootDSE)).
I would not rely on uid being the proper search attribute for the user entries in LDAP. Many companies will only guarantee the employeeID as being unique within the LDAP DIT.
You need to define what container to start searching in. So this would be something like
"LDAP://" + _ADSPath + ":" + _ADSPort + "/" + _ADSRootContainer
where _ADSPath is the server hostname/ip; _ADSPort is the port number (usually 389 by default); and _ADSRootContainer is the rest of the path to the container (like ou=Users.
The path would depend on the implementation you are searching against. You can start up higher than the container holding the users and set the parameters on the search object to use a multi-level search. But it will be much slower.