How to negate a parameter in search request in Swagger? - api

I am writing my first Swagger spec for a search endpoint and wondering if there is a simple way to negate a search parameter.
Here is the yml for searching by brand:
properties:
brand:
description: The magazine that produced the original article
type: string
I would also like our users to be able to search by excluding a brand (eg either "from [brand]" or "not from [brand]". Is there a more graceful approach than creating duplicate properties for each parameter (eg, both brand and notBrand)?

I'd suggest the following. If you are using query parameters for the search endpoint (which is probably smart), you should consider having a querystring parameter like such:
- name: brand
in: query
type: array
items:
type: string
You can have another query parameter for excludes which follows the same syntax. Be sure to set the collectionFormat depending on how your API will parse the query string, since arrays are simply not standardized across frameworks. Read here for more details.

Related

Representing complex data types in XACML using Authzforce

I am new to XACML and I would be grateful if you can help me with one problem I encountered.
I use AuthzForce Core PDP (version 17.1.2).
I am wondering what is the correct approach of representing complex data types in XACML.
Example
Access should be granted if PIP response contains any person whose name is present in names array from request and salary of that person is higher than salary provided in request.
Request
names = ["Eric", "Kyle"]
salary = 1500
PIP response
[
{
"name": "Kyle",
"salary": 1000
},
{
"name": "Kenny",
"salary": 2000
},
{
"name": "Eric",
"salary": 4000
},
{
"name": "Stan",
"salary": 3000
}
]
Access will be granted because PIP response contains person with name Eric and his salary is higher than 1500.
My implementation
To represent PIP response I ended up with creating custom type by extending StringParseableValue class from AuthzForce. For above mentioned logic I use attribute designator in xml and have coresponding attribute provider (class extending BaseNamedAttributeProvider) in Java performing PIP call.
I also wrote two custom functions:
Find people with higher salary than provided in one param (returns filtered list)
Get person name (returns string)
And using those functions and standard function I wrote policy and it works.
However my solution seems to be overcomplicated. I suppose what I did can be achieved by using only standard functions.
Additionally if I wanted to define hardcoded bag of people inside other policy single element would look like this:
<AttributeValue DataType="person">name=Eric###salary=4000</AttributeValue>
There is always possibility that parsing of such strings might fail.
So my question is: What is a good practice of representing complex types like my PIP response in XACML using Authzforce? Sometimes I might need to pass more complex data in the request and I saw example in XACML specification showing passing such data inside <Content> element.
Creating a new XACML data-type - and consequently new XACML function(s) to handle that new data-type - seems a bit overkill indeed. Instead, you may improve your PIP (Attribute Provider) a little bit, so that it returns only the results for the employees named in the Request, and only their salaries (extracting them from the JSON using JSON path) returned as a bag of integers.
Then, assuming this PIP result is set to the attribute employee_salaries in your policy (bag of integers) for instance, and min_salary is the salary in the Request, it is just a matter of applying any-of(integer-less-than, min_salary, employee_salaries) in a Condition. (I'm using short names for the functions by convenience, please refer to the XACML 3.0 standard for the full identifiers.)
Tips to improve the PIP:
One issue here is performance (scalability, response time / size...) because if you have hundreds even thousands of employees, it is overkill to get the whole list from the REST service over and over, all the more as you need only a small subset (the names in the Request). Instead, you may have some way to request the REST service to return only a specific employees, using query parameters; an example using RSQL (but this depends on the REST service API):
HTTP GET http://rest-service.example.com/employees?search=names=in=($employee_names)
... where you set the $employee_names variable to (a comma-separated list of) the employee names from the Request (e.g. Eric,Kyle). You can get these in your AttributeProvider implementation, from the EvaluationContext argument of the overriden get(...) method (EvaluationContext#getNamedAttributeValue(...)).
Then you can use a JSON path library (as you did) to extract the salaries from the JSON response (so you have only the salaries of the employees named in the Request), using this JSON path for instance (tested with Jayway):
$[*].salary
If the previous option is not possible, i.e. you have no way of filtering employees on the REST API, you can always do this filtering in your AttributeProvider implementation with the JSON path library, using this JSON path for instance (tested with Jayway against your PIP response):
$[?(#.name in [$employee_names])].salary
... where you set the $employee_names variable like in the previous way, getting the names from the EvaluationContext. So the actual JSONpath after variable replacement would be something like:
$[?(#.name in [Eric,Kyle])].salary
(You may add quotes to each name to be safe.)
All things considered, if you still prefer to go for new XACML data-type (and functions), and since you seem to have done most of the work (impressive btw), I have a suggestion - if doable without to much extra work - to generalize the Person data-type to more generic JSON object datatype that could be reused in any use case dealing with JSON. Then see whether the extra functions could be done with a generic JSONPath evaluation function applied to the new JSON object data-type. This would provide a JSON equivalent to the standard XML/XPath data-type and functions we already have in XACML, and this kind of contribution would benefit the AuthzForce community greatly.
For the JSON object data-type, actually you can use the one in the testutils module as an example: CustomJsonObjectBasedAttributeValue which has been used to test support of JSON objects for the GeoXACML extension.

Why does GraphQL query work with the "query" keyword before the curly braces?

I created a small API for authors and books as example. The problem is that I don't understand why a query can look different but still get me the same output. I've included 3 examples.
The GraphQL query looks like this:
{
"query":
"query{
author(id: 1) {
name
}
}"
}
Why is this query working if within the query is the keyword "query" two times? When I write the query like this:
{
"query":
"{
author(id: 1) {
name
}
}"
}
it also works, and when I write it like that:
{
"query":
"author{
author(id: 1) {
name
}
}"
}
It is not working. Why is that so?
GraphQL specifies three types of operations:
query – a read‐only fetch.
mutation – a write followed by a fetch.
subscription – a long‐lived request that fetches data in response to source events.
What you are sending to your server is a JSON object with a single property (query) the value of which is a GraphQL document that represents your actual request to the GraphQL service. This property is (unfortunately) called query by convention but it has nothing to do with the actual operation inside the document you are sending.
Any operation included in your GraphQL document must follow this format:
OperationType [Name] [VariableDefinitions] [Directives] SelectionSet
Name, VariableDefinitions and Directives are all optional. The OperationType is one of query, mutation or subscription. SelectionSet is the collection of fields you are requesting for that operation type. Only selection sets are wrapped in curly brackets. In your example, you have two selection sets -- one containing the author field and one containing the name field.
There's an exception to the above called query shorthand:
If a document contains only one query operation, and that query defines no variables and contains no directives, that operation may be represented in a short‐hand form which omits the query keyword and query name.
In other words if your operation:
is a query
is the only operation in the document
contains no variable definitions or directives
You can omit the query keyword and the operation name. This leaves you with just a selection set, which is wrapped in a set of curly brackets.
So your first two examples are equally valid. The third example is not valid because author is not a valid operation kind.
The first query key on your examples is a requirement from GraphQL to actually call the endpoint, it has to be present to actually run queries or mutations. You can see it in the docs.
The first example works because at the root of a GraphQL Schema there has to be an action with keywords query or mutation, and in your case you are triggering a query.
The second example works because if you don't define what type of action (query or mutation) on your request, it always defaults to execute a query.
The third example does not work because you don't have the action author at the root of your Schema.
I guess the first keyword query is what makes some confusion in this case.

Zapier lazy load input fields choices

I'm building a Zapier app for a platform that have dynamic fields. I have an API that returns the list of fields for one of my resource (for example) :
[
{ name: "First Name", key: "first_name", type: "String" },
{ name: "Civility", key: "civility", type: "Multiple" }
]
I build my action's inputFields based on this API :
create: {
[...],
operation: {
inputFields: [
fetchFields()
],
[...]
},
}
The API returns type that are list of values (i.e : Civility), but to get these values I have to make another API call.
For now, what I have done is in my fetchFields function, each time I encounter a type: "Multiple", I do another API call to get the possible values and set it as choices in my input field. However this is expensive and the page on Zapier takes too much time to display the fields.
I tried to use the z.dehydrate feature provided by Zapier but it doesn't work for input choices.
I can't use a dynamic dropdown here as I can't pass the key of the field possible value I'm looking for. For example, to get back the possible values for Civility, I'll need to pass the civility key to my API.
What are the options in this case?
David here, from the Zapier Platform team.
Thanks for writing in! I think what you're doing is possible, but I'm also not 100% that I understand what you're asking.
You can have multiple API calls in the function (which it sounds like you are). In the end, the function should return an array of Field objects (as descried here).
The key thing you might not be aware of is that subsequent steps have access to a partially-filled bundle.inputData, so you can have a first function that gets field options and allows a user to select something, then a second function that runs and pulls in fields based on that choice.
Otherwise, I think a function that does 2 api calls (one to fetch the field types and one to turn them into Zapier field objects) is the best bet.
If this didn't answer your question, feel free to email partners#zapier.com or join the slack org (linked at the bottom of the readme) and we'll try to solve it there.

How to filter fields in documents with security rules

I am experimenting with Cloud Firestore security rules. Is it possible to filter document fields?
For example if you have a document
{
name: "John Doe",
email: "doe#example.com"
}
then some users aren't allowed to get the document with the email address. Their application requests the document with
firebase.firestore.doc('users/doe-uid')
and gets this document
{
name: "John Doe",
}
If yes, how?
I think it should be possible because the Cloud Firestore Security Rules Reference says in the first sentence (emphasis is mine):
Cloud Firestore Security Rules are used to determine who has read and write access to collections and documents stored in Cloud Firestore, as well as how documents are structured and what fields and values they contain.
However I couldn't find anything in the reference telling me how to filter out fields.
Firestore rules are not filters, they're a server-side validation of document queries, meaning that you access (or not) the whole document, not particular fields.
The piece of documentation you mentionned means that you can do data validation on fields.
Here is a basic example of rules validating data on a write query (via request.resource.data) :
match /users/{userId} {
allow write: if request.resource.data.age is int;
}
Here is another basic example that uses an existing field to validate a read query (via resource.data) :
match /articles/{articleId} {
allow read: if resource.data.isPublished == true;
}
To filter out fields, you have do it client side, after the query.
Now If you want to secure access to certain fields, you have to create another collection (look into subcollections) with a different set of rules, and make another query that will match these rules.

Filter RavenDB Search Results

I have a query that returns valid search results using the IRavenQueryable.Search method. However, I want to further filter those results via a .Where method call such that the search results are then filtered to only include those that have the matching ProjectId.
My object structure is a set of Project entities each containing a collection of Issue entities.
My index creates a projection of Issue Search Results that looks like:
{Id, Key, Summary, Description, ProjectId, ProjectKey, Query}
The Query property is an object[] that is used by the keyword search.
When I run the keyword search:
var results = session.Query().AsProjection().Search(x => x.Query, "some key word");
I get the right results back. But when I try to also apply the Where method:
results = results.Where(i => i.ProjectId == SelectedProject.Id);
It does not filter the results, but instead includes all other results with matching Project Id's.
What is the correct way to force Linq or RavenDB's IRavenQueryable to apply an AND instead of an OR in this scenario?
After posting this question I managed to find the answer elsewhere on stackoverflow.
Here is the solution:
ravendb combining Search with Where
In a nutshell, the Search method provides an extra optional parameter [options] to allow you to specify how the search is combined with other where clauses in the query. It defaults to SearchOptions.Or so you need to explicitly set it to options: SearchOptions.And.