Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
query-bouncer
Advanced tools
The Goal of Query Bouncer is to let you worry about your application and not about your Authentication and Authorization in a Container Environment.
The Goal of Query Bouncer is to let you worry about your application and not about your Authentication and Authorization in a Container Environment.
The Query Bouncer is a containerized Microservice to work together with rm-Authenticator as a versatile Role Based Access Control System for your Application.
It will do that by adjusting a database query sent from the backend in alignment with a users permissions. The updated query will be sent back and can be used to retrieve data from the database that the user is allowed to see/create...
The upside is that the Query bouncer will never handle your live business data but will only adjust queries you make to the database.
Currently only Queries for MongoDB are supported.
There are two components that are mandatory if you want to use the Query Bouncer. You'll need a running instance of rm-authenticator and the query-bouncer itsself. If you are using node.js as Backend we also recommend using the query-bouncer and the rm-session-populate as plugins to further make the use easier and enable you to focus on writing your application.
Here the core elements of the Query Bouncer will be described. Of course you can insert them manually in your database. But this section is here for understanding how these elements are connected and work together. To manage those connections please refer to the API
Permissions are the basis of everything. A typical Permission to grant read access will look like this
{
"Title": "readFavoriteBlogPosts",
"Collection": "blogposts",
"Right": "read",
"QueryRestriction" : {
"Topic" : "${Topic}"
}
}
Internal Permissions work in just the same way as regular ones do. But they manage Permissions for the Query Bouncer itsself. So in many cases you might want someone to be able to assign Roles to other users without giving them your admin Token to the service. Let's assume you want to assign an admin for your BlogPosts that is able to grant other People a Role of a Blogger. But the restriction is that this admin can only grant this permission if the Topic he wants this user to be able to read matches the one assigned for him as well. Then the internal Role Assignment would look like this. Don't worry too much about the Data Field in the PayloadRestriction. It will be explained in more detail in the RoleAssignment Section
{
"Title": "AssignBlogger",
"Collection": "roleassignments",
"Right": "create",
"PayloadRestriction" : {
"Data": {
"Topic": "${Topic}"
}
}
}
The Title just identifies the permission and will be used to add it to the later described roles
The collection this permission refers to. In this fictional case we grant rights to read documents in the blogposts collection
The right this permissions grants. In this case "read". It could also be "create", "update" or "delete"
The QueryRestriction is used to restrict the Query made to the database. For Read and Delete Operations only the QueryRestriction is available. Later we will also see the PaloadRestriction. in this case we restrict the read permissions to documents that only have a certain value for the Topic Key. We could just use a fixed value like "Food" here, but we can also use a placeholder. We will describe the placeholder in more detail in the Section of RoleAssignments later but for now just think that this value can differ from user to user later. You can also use nested QueryRestrictions or basically any Query you know from MongoDB
The PayloadRestriction is only available for Permissions of the Right "create" and "update". "update" contains a QueryRestriction additionally, "read" and "delete" only contain QueryRestrictions. The purpose of the PayloadRestriction is to restrict the payload a user can send. If we take our current example let's say the user was only able to create Blogposts in his favorite category. So the create Permssion would look like this
{
"Title": "createFavoriteBlogPosts",
"Collection": "blogposts",
"Right": "create",
"PayloadRestriction" : {
"Topic" : "${Topic}"
}
}
You see the actual structure of the PayloadRestriction is basically the same as the query restriction. The takeaway is that the QueryRestriction restricts everything you get from the database. The PayloadRestriction restricts everything you put into the database. That is why the "update" right needs both the Payload and the QueryRestriction. As you first have to determine if you are allowed to get the document you want to change as well as validate the information you want to put into the document.
Multiple permissions are combined with a logical OR, so more permissive permissions overwrite less permissive restrictions. Payload restrictions within the same permission are combined with a logical AND, so the payload or query has to match all criterias.
Given these two permissions for a user, the upper one is more permissive (by allowing writing to a topic independent of the author) and effectively overwrites the lower one.
{
"Title": "writeBlogPosts",
"Collection": "blogposts",
"Right": "write",
"QueryRestriction" : {
"Topic" : "${Topic}"
}
}
{
"Title": "writeBlogPosts",
"Collection": "blogposts",
"Right": "write",
"QueryRestriction" : {
"Topic" : "${Topic}",
"Author" : "${Author}"
}
}
Roles are used to aggregate permissions to a certain role. In our current example a role could look like this
{
"Title": "DefaultUser",
"Permissions": [
"readFavoriteBlogPosts",
"deleteOwnBlogPosts",
"updataOwnBlogPosts",
"createBlogPostsInFavoriteCategory"
]
}
The Title is also used to identify the Role and to use it in the RoleAssignments
An Array with all the Permissions you want to grant with that role. The entries are the titles of those Permissions, not their _id
Finally we want to assign those roles to users. A role assignment for the given example could look like this
{
"User": "john.doe@hotmail.com",
"Role": "DefaultUser",
"Data": {
"Topic": "Cars"
}
}
You can assign as many roles to a user as you want to, but every Role Assignment will only contain a single role. So if you want to do that create multiple role assignments each containing exactly one Role.
The Identification of the user. The Authenticator will send back user information. In the section Environment Variables you can see how to set which of those parameters you want to use as identification. By default it is the _id of the user but in this case we went with email for a better understanding. There are also special users you can assign.
$anyone: will be a RoleAssignment that is valid for anyonone making a web request.
$authenticated: is the special user that makes this role assignment valid for any user that has been authenticated by the Authenticator and whose user object contains a value for the user primary identification key (see the correspoding part in the environment variables about QBOUNCER_USER_PRIMARY_KEY for more information)
The Role you want to assign. It has to be exaclty one role you assign. In this case its the DefaultUser Role we created in the previous section. If John Doe was also an admin we could also create a second Role Assignment with that role and he would have all the permissions granted by those two roles
Remember the Placeholder for the QueryRestriction we used in the Permission Section. Now we can set this individually for our John Doe. So in in this case when John Doe later tries to access all BlogPosts from the Database the Authenticator will adjust the Query to only return BlogPosts from the Topic Cars. Just make sure that all the Placeholders used in any permissions the user has also need to have Data in here.
Several things can and need to be configured for the Query Bouncer to run properly. Those will contain Settings for the Authenticator, the Web Server, Main Settings and the MongoDB you are using to store all the Permissions, RoleAssignments, etc. The following instructions will be the environment variables you use to configure the Query Bouncer
As mentioned earlier, the Query Bouncer will send you back a user object containing multiple key/value-pairs. By default The Query Bouncer will use the _id of a user as a unique identifier, but you can also use email for example
The Admin Token will be used to access the Query Bouncer without restrictions. Only Admins will be able to set Roles and Permissions, but RoleAssignments will also be available users with according rights
The Query Bouncer is pretty tightly paired with the Authenticator. The Authenticator will handle session management and determine who is using your application and the Query Bouncer will determine what the user is allowed to do and what not.
The Host where the Query Bouncer will be able to reach the Authenticator. Defaults to http://localhost:8081 if you are hosting it on your machine as well for testing purposes
Port you want to use for the main API: Defaults to 8080
Port you Metrics will be available. Those can be scraped by Prometheus (still a work in progress and not ready). Defaults to 9100
Host of the MongoDB. Defaults to localhost
Port of the MongoDB. Defaults to 27017
Database where Authenticator stores its Data. Defaults to query_bouncer
Database you will authenticate your user against. Defaults to admin
Username for MongoDB
Password for your user
Create a new Permission. See Permissions for details.
URL:
/api/admin/permissions
/api/admin/internalPermissions
Method: POST
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"PayloadRestriction": {
"Category": "${Category}"
}
}
Code: 201
Response Data Example
{
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"PayloadRestriction": {
"Category": "${Category}"
}
}
Get all Permissions currently available. If you have not already specified a Permission Role and InternalRoleAssignment for your user make sure you use the bearer token to authenticate
URL:
/api/admin/permissions
/api/admin/internalPermissions
Method: GET
Auth required: YES
Auth Type: Bearer Token (Cookie if proper RoleAssignment present)
Code: 200
Content Example
[{
"_id": "5b637ee00000000000000000",
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"QueryRestriction" : {},
"PayloadRestriction": {}
}]
Update an existing Permission. See Permissions for details.
URL:
/api/admin/permissions/:PermissionTitle
/api/admin/internalPermissions/:PermissionTitle
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if proper RoleAssignment present)
Request Body Example
{
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"PayloadRestriction": {
"Category": "${Category}"
}
}
Code: 200
Response Data Example
{
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"PayloadRestriction": {
"Category": "${Category}"
}
}
Delete a Permission
URL:
/api/admin/permissions/:PermissionTitle
(/api/admin/internalPermissions/:PermissionTitle
)
Method: DELETE
Auth required: YES
Auth Type: Bearer Token (Cookie if proper RoleAssignment present)
Code: 200
Request Body Example
{
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"PayloadRestriction": {
"Category": "${Category}"
}
}
Get all Permissions of the currently authenticated user currently available. The permissions will be populated, so Data from the RoleAssignments is already replaced in the restrictions.
URL:
/api/admin/permissions/myPermissions
/api/admin/internalPermissions/myPermissions
Method: GET
Auth required: YES
Auth Type: Bearer Token with JWT
Code: 200
Content Example
In this example the current user has two RoleAssignments. Both grant the right to read blogposts but one is for the Category Cars, the other for Food. So two permissions are returned and the query restriction is populated with the two values.
[{
"_id": "5b637ee00000000000000000",
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"QueryRestriction" : {"Category": "Cars"},
"PayloadRestriction": {}
},
{
"_id": "5b637ee00000000000000000",
"Title": "ReadBlogPosts",
"Collection": "blogposts",
"Right": "read",
"QueryRestriction" : {"Category": "Food"},
"PayloadRestriction": {}
}
]
Create a new Role
URL: /api/admin/roles
Method: POST
Auth required: YES
Auth Type: Bearer Token (Cookie if proper RoleAssignment present)
Request Body Example
{
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts"
]
}
Code: 201
Success Response Body Example
{
"_id": "5b637ee00000000000000000",
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts"
]
}
Get Roles currently available
URL: /api/admin/roles
Method: GET
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Code: 200
Success Response Body Example
[{
"_id": "5b637ee00000000000000000",
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts"
]
}]
Update an existing Role
URL: /api/admin/roles/:RoleTitle
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts",
"DeleteOwnPosts"
]
}
Code: 200
Success Response Body Example
Request Body Example
{
"_id": "5b637ee00000000000000000",
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts",
"DeleteOwnPosts"
]
}
Delete an existing Role
URL: /api/admin/roles/:RoleTitle
Method: DELETE
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
Code: 200
Success Response Body Example
Request Body Example
{
"_id": "5b637ee00000000000000000",
"Title": "FoodBlogger",
"Permissions": [
"ReadBlogPosts",
"CreateFoodBlogPosts",
"DeleteOwnPosts"
]
}
Create a new RoleAssignment. Keep in mind that user has to match the userPrimaryKey described in the Configuration Chapter. In this case we assume that it is the E-Mail.
URL: /api/admin/roleAssignments
Method: POST
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Food"
}
}
Code: 201
Success Response Body Example
{
"_id": "5b637ee00000000000000000",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Food"
}
}
Get all current Role Assignments
URL: /api/admin/roleAssignments
Method: GET
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Code: 200
Success Response Body Example
[{
"_id": "5b637ee00000000000000000",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Food"
}
}]
Update an existing Role Assignment
URL: /api/admin/roleAssignments/:Id
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Cars"
}
}
Code: 200
Success Response Body Example
{
"_id": "5b637ee00000000000000000",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Cars"
}
}
Delete an existing Role Assignment
URL: /api/admin/roleAssignments/:Id
Method: DELETE
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Code: 200
Success Response Body Example
{
"_id": "5b637ee00000000000000000",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Cars"
}
}
Get all Role Assignments for the currently logged in user
URL: /api/admin/roleAssignments/myRoleAssignments
Method: GET
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Code: 200
Success Response Body Example
[{
"_id": "5b637ee00000000000000000",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Food"
}
},
{
"_id": "5b637ee00000000000000001",
"User": "john.doe@hotmail.com",
"Role": "FoodBlogger",
"Data": {
"FavoriteTopic": "Car"
}
}]
If you are using mongoose we suggest the according plugin. However if you have a more specific usecase or are using a different framework you can also make requests to Query Bouncer yourself. E.g. given if Query Bouncer is set up like described in the previous chapter you can check if a user may upload a file like this
URL: /api/v1/blogposts/read
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"query" : {
"Title" : "My Favorite Food"
}
}
Code: 200
Success Response Body Example
{
"query": {
"Title" : "My Favorite Food",
"Category" : "Cars"
}
}
To check the payload for permission use the following request. If the user may upload the file query bouncer will return 200. If not 403 will be returned
URL: /api/v1/blogposts/create
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"payload" : {
"Title" : "My Favorite Car",
"Category": "Cars"
}
}
Code: 200
To adjust the query to delete a document use the following request. Query bouncer will return a query that matches the permissions of the user. If no permisson was found it will return 403. E.g if you would try to delete a document from blogposts and specify an id but that document would not also match the Category it is allowed to be in the query will return no documents after it has been populated and no documents will be deleted
URL: /api/v1/blogposts/delete
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"query" : {
"_id" : "SomeId"
}
}
Code: 200
Success Response Body Example
{
"query": {
"_id" : "SomeId",
"Category" : "Cars"
}
}
To update a document you will need both. A query that matches the document to be updated and the payload for the new document. If everything is ok you will get a payload and a query returned with a status of 200. If the payload does not match the restrictions 403 will be returned instead.
URL: /api/v1/blogposts/update
Method: PUT
Auth required: YES
Auth Type: Bearer Token (Cookie if InternalRoleAssignment present)
Request Body Example
{
"query" : {
"_id" : "SomeId"
},
"payload" : {
"Title": "Not my favorite car anymore"
}
}
Code: 200
Success Response Body Example
{
"query": {
"_id" : "SomeId",
"Category" : "Cars"
},
"payload" : {
"Title": "Not my favorite car anymore"
}
}
There's more work to do. The most recent additions will be
Eventually we will also add
FAQs
The Goal of Query Bouncer is to let you worry about your application and not about your Authentication and Authorization in a Container Environment.
The npm package query-bouncer receives a total of 1 weekly downloads. As such, query-bouncer popularity was classified as not popular.
We found that query-bouncer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.