aldoportillo

Aldo Portillo

Posted on November 15, 2023

Authorization

Authorization

Introduction

Although I am fortunate enough to develop software during the week, I still get the pleasure of being employed as a server and bartender. My current service industry employer is making huge changes on structure, and I am very excited for it; however, with change there is always resistance. During one of our wine meetings, there was talk about having an anonymous box where employees can submit anonymously make comments about the changes and suggestions. Considering we have 4 locations, and I was speaking to one of the higher ups. I thought it would be a great idea to create a anonymous box backend.

Models

In terms of structuring the database, Users and Posts were a given. At first, I thought to myself since they were anonymous. I can just render all the posts to the admin and none to the user; however, I had to think ahead a bit. Although the suggestion was to only use it for the Oak Park location, I am hopeful that I will be used for our other locations. So I also made a restaurants table, to allow admin to view posts by location.

So what did I need to do to secure the posts from the outside world? Easy, authenticate user. If user isn't authenticated, make them login or register. It's miller time. No its not. We don't really care if some random person in the world reads what Bob had to say about his coworker Mallory (kinda), we care about making sure Mallory never reads what Bob said. Well lets find those vulnerabilities.

Routes, Controllers and Actions

There are a some routes that we want some users to access but not others:

  • Post Routes: We want the user to either be admin or author view the post; otherwise, redirect to home. Although there is no direct link in the app to navigate to one's post. It doesn't take a rocket scientist to figure out the routes to a RESTful app.

There are a some routes that we want some users to access but not others:

  • Restaurant Routes: We only want the admin to view these routes. Since not only do they contain the power to create restaurants and read all posts associated with the restaurant, but they also can delete a restaurant. That is a huge loss of data. Not good.

Implementation

  1. Include Pundit in ApplicationController

    #app/controllers/application_controller.rb
    include Pundit
    
  2. Generate Pundit Policy Files
    Run "rails g pundit:policy policy_name" in bash

  3. Write authorization logic in policy files. For posts, I actually used a scope.

    # In app/policies/post_policy.rb
    class PostPolicy < ApplicationPolicy
        attr_reader :user, :post
    
        def initialize(user, post)
            @user = user
            @post = post
        end
    
        def index?
            user.present?
        end
    
        def show?
            scope.where(:id => post.id).exists?
        end
    
        def update?
            user.admin? || post.user == user
        end
    
        def destroy?
            user.admin? || post.user == user
        end
    
        class Scope < Scope
            def resolve
                user.admin? ? scope.all : scope.where(user: user)
            end
        end
    end
    
  4. Implement Authorization in Controllers

    #In app/controllers/post_controller.rb
    class PostController < ApplicationController
        ...
        # GET /posts or /posts.json
        def index
            # @posts = Post.all
            @posts = policy_scope(Post)
        end
        def show
            authorize @post
        end
        ...
    end
    
    
  5. Handle Pundit::NotAuthorizedError in Application Controller by rescuing it.

    #In app/controllers/application_controller.rb
    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
    
    private
    
    def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    redirect_to(request.referrer || root_path)
    end
    

Conclusion

And just like that, the posts are protected from other users and the world. The only people allowed to see them are admin and author. Also I definitely recommend Vezzi Barbera. Had 2 glasses when writing this article. Nice medium body+, slightly acidic, dry wine.

💖 💪 🙅 🚩
aldoportillo
Aldo Portillo

Posted on November 15, 2023

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

Sign up to receive the latest update from our blog.

Related

Authorization
rails Authorization

November 15, 2023