Starchart: Matching Database With SAML Claims

cychu42

cychu42

Posted on March 11, 2023

Starchart: Matching Database With SAML Claims

Task

What I did this week was matching User table of database in Starchart project with what useful information SAML would return about users when users log in.
This meant adding group column in User table in database, given it's one of the claims. group claim is used as role assignment, such as user being part of student group, which has specific access attached to the group.
This project uses Prisma to interact with the database.

There were 3 things I needed to do:

  1. Edit the schema file (prisma\schema.prisma).
  2. Edit the file (prisma\seed.ts) for seeding to make sure these seeded users have groups.
  3. Chang how relevant functions interact with the database, so a function that make Prisma API call to create a user would need to be changed for the addition of group. When changing a function definition, one needs to remember to change how the function is used in other area of your code. For example, I changed the parameter of createUser() to allow argument for group, so I must change how the function is used elsewhere in the project too.
  4. Cover new use cases for the column. This meant I added 3 functions to check whether a user belongs to one of 3 groups. The functions isStudent(), isFaculty(), and isAdmin() accept username as parameter. They would return true if they have the role/group, false if not. The code look something like this:

     export async function isFaculty(username: 
     PrismaUser['username']) {
       const { group } = await prisma.user.findUniqueOrThrow({ where: { username } });
       // The group will have -dev in it on staging but not on prod
       return /mycustomdomain(-dev)?-faculty/.test(group);
     }
    

    async marks this function as asynchronous, since it needs to interact with the database and await a response.

    The group value will be returned by the Prisma function after it fetches the user, by using the primary key username. Notice typescript syntax is used to limit the type of username according to Prisma User model's username column type.]
    findUniqueOrThrow() will throw error if nothing is found, as the function name suggests. You can see the documentation here.

    After group is returned, a regular expression is used and test against the group value. If there's a match, it will return true, or false in the case of no match. This looks for any mycustomdomain-faculty or mycustomdomain-dev-faculty in group.

  5. Consider other adjustment to codes relating to User. There was no need for additional adjustment for this, but I could easily needed to do so. For example, if I changed a column name, I would need to change other references to the name in the project.

Also, I merged firstName and lastName columns into one displayName column, given that's what SAML gives back. The same ideas for such changes in database schema apply: edit the schema file, edit the seeding file, change/add relevant functions, and other relevant code adjustment. In this case, no new function was added.

Change Log Of The PR:

  • Add group in User model as String in prisma\schema.prisma
  • Add examples in prisma\seed.ts
  • Modify createUser() in app\models\user.server.ts accordingly
  • Add isStudent(), isFaculty(), and isAdmin() in app\models\user.server.ts.
  • Combine firstName and lastName into displayName
  • Modify arguments of createUser() in app\routes\login\callback.tsx

isStudent(), isFaculty(), and isAdmin() accept username as parameter. They would return true if they have the role/group, false if not.

💖 💪 🙅 🚩
cychu42
cychu42

Posted on March 11, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related