Is there any way to apply field level authorization while writing/updating in mongodb? - spring

I know there are various Role based authentication/authorisation available for mongodb on db as well as collection level. But Is there any way to implement authorisation on field level inside collection?
For example:
Their is a collection user:
User :{
id: String,
name: String,
roles: ArrayList,
....
}
So here I want to give access of writing/updating the roles to only DB admin and the rest fields can be updated by anyone.
Is there any way to implement this on DB layer only without going to application layer?
If yes, Then how to implement that using Spring boot ?

Related

How to inject a value via middleware into a graphql query body (prisma-typegraphql)?

I am currently using prisma-typegraphql for generating a schema and it's props.
Problem:
Is there a way to write a middleware that accesses a value from an arbitrary source, then injects that into the graphql-query arguments? It should be passed to the resolver in a way that makes it seem like the data has been in the query from the start and no modification to the resolver is necessary.
More info
Let's say I have three models, one is Client, one is Project and one is User. The Project has a relationship to the client via its id, identifying the client the project belongs to, same for the user
model Client{
id
name
etc...
}
model User{
id
name
clientId / client
etc...
}
model Project{
id
title
clientId / client
etc...
}
I don't want the clientId from the frontend via query, instead I intend to verify the user making the request and then get the clientId from that user.
Currently my Auth Middleware does verify the user and then passes the user object along in the context. However, due to the generated nature of typegraphql-prisma resolvers, I cannot use the context to inject the data into the resolver without extending every single resolver.
I'd much rather inject the value I want into the graphql query before it reaches the resolver, so the resolver has no idea something changed and processes the query as intended.

Conceptual Question: Shared GraphQL schema for multiple endpoints (client/admin)

Context
I am using a NX Workspace to organize two different angular frontends (client & admin). To separate client and admin logic, two different NestJS backend services including GraphQL are used for client and admin.
As both services fetch data from a single MongoDB a single database library is used for both frontends.
Both backend services currently use a single GraphQL Schema generated through schema-first approach and a single database layer. In most cases the types and fields definition matches between client and admin, but in some cases a single service requires additional query arguments or fields.
For example, the admin service depends on the fields confirmed or banned of type User while they shouldn't be available through the client service.
Furthermore, e.g. the getUsers query should not be exposed through the client service.
type User {
_id: ID
name: String
email: String
confirmed: Boolean
banned: Boolean
}
type Query {
getUserById(userId: String): User
getUsers(): [User]
}
Question
Are there any best practices how to proceed with the GraphQL Schema(s) in such a case as the types are almost similar.
You can use schema directives to define authorization rules in a declarative manner directly in your Graphql schema.
A common approach would be to assign roles to a user and then use these roles to allow/block access to certain mutations or queries.
So for your example, I would imagine any request coming from the client would be made by a user with a role of client and any request coming from admin would have a user role of admin
So to build on your example of limiting the getUsers query to just admins we could add this directive to our schema:
type User {
_id: ID
name: String
email: String
confirmed: Boolean
banned: Boolean
}
type Query {
getUserById(userId: String): User
getUsers(): [User] #hasRole(roles: [admin])
}
You can read more about how to actually implement the custom directive hasRoles in the nestJs docs https://docs.nestjs.com/graphql/directives

How to access different database based on different user in Spring Data Mongodb environment?

In my current implementation, MongoDB architecture looks like
DB : schoola
Collections :
1. students
2. users
DB : schoolb
Collections :
1. students
2. users
And in each instance of Spring Server properties file I do -
SPRING_DATA_MONGODB_DATABASE: <dbname>
SPRING_DATA_MONGODB_URI: <URI to <dbname>>
Clearly this isn't scalable and I am already tired of maintaining different server instances.
Instead what I am looking for I will have a User DB
DB : user
Collections :
1. users (with fields {userName, password, associatedWith: <DB NAME OF THE SCHOOL USER IS ASSOCIATED WITH>)
So how do I do the following?
When the user tries to login in I try validate with user/users and if success I fetch the associatedWith value.
Then I connect to that DB and provide services to that user, again I don't to connect to mongodb with every Rest call, probably I need to maintain a userContext in memory.
One way of doing this would be to provide your own flavour of a MongoDatabaseFactory, that on getMongoDatabase(), reads the tenant from a context source and returns the MongoDatabase to use.
This sample is a bit dated but gives an impression of the overall direction here.

CrudRepository save function updating deleted entities

I am using the Spring Boot with Spring JPA and CrudRepository and I am wondering if there is any way the save function could detect deleted nested entities and update that as deleted or do I have to call the delete function on every deleted nested item.
Let's say I have this:
user: {
name: 'John Smith',
profile: {
experience: [
{
job: 'Google',
role: 'System admin'
},
{
job: 'Apple',
role: 'Platform manager'
}
]
}
}
Now, in my code as it is now if I change the name and add an experience and then hit the save button the CrudRepository's save function solves that just by saving the user object since I have all my items connected with the annotations #oneToOne, #oneToMany and #manyToOne.
My question is, what if I change the name, add an experience AND remove another experience? The save function in CrudRepository does not consider entities that are deleted within the object coming from frontend as DTO converted to JPA.
I want my users to be able to edit their profile page as much as they want, meaning: changing states, adding items or removing items. THEN hit the save button and the user object will be save as the new edited user object.
I hope this is making any sense.
Thanks
You should make a separate restful endpoint for managing the experience entries:
POST /users/1/experiences - create new experience entry
DELETE /users/1/experiences/1 - remove an experience entry from user
PUT/PATCH/POST(whatever you want) /users/1/experiences/1 - update an experience entry
Either you manage it like that or if you want to stick with what you have every time a user is saved you should remove all their experience entries from the database and replace with the fresh data from your DTOs. Will make your life much easier.

Java webapp API id-based security filter

We're building our API and looking for an organized way to grant users access based on what role and permission they have.
From the starting point, we have 3 roles
Admin: can get and edit everything in his organization
Team Admin: can get and edit only his team info and users' info
User: can get any edit his own information
Entity
Team
User
For Security Filters:
We're using JAX-RS with Security Roles and #RoleAllowed to filter access to resources
Id-based filter by if / then / else function. Example with a team admin access to a user.
function isAllowAccess(teamAdminId, userId) {
allowedUserIdsList = queryfor(teamAdminId);
if (userId in allowedUserIdsList) then ... else BAD_REQUEST
}
This code is growing with the increase complexity of multiple roles and many entities. So my questions:
What will be the best way to have an organized id-based filter, is there reputable library for this?
Should we maintain a separate table containing accessible ids of each
entity for each team_admin_id? Then every row updated or inserted will trigger the update of this table.
Is there a formal or widely acceptable method to reduce database
call overhead in each call just to check if the team_admin is
allowed to access a particular user?

Resources