Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Role authorization #3

Merged
merged 4 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/rspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ jobs:
- name: Run rspec
env:
DATABASE_URL: ${{ steps.setup.outputs.database_url }}
rspec_oscal_timestamp: false
run: bundle exec rspec

- name: Save assessment results
uses: actions/upload-artifact@v4
with:
name: continuous_monitoring_assessment
path: tmp/oscal_assessment
17 changes: 12 additions & 5 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,29 @@ end

gem "secure_headers", "~> 6.3"

gem "sidekiq", "~> 7.2"

gem "pundit", "~> 2.3"
gem "devise", "~> 4.9"

group :development, :test do
gem "rspec-rails", "~> 6.1"
gem "dotenv-rails", "~> 3.1"
gem "brakeman", "~> 6.1"
gem "bundler-audit", "~> 0.9"
gem "standard", "~> 1.36"
gem "i18n-tasks", "~> 1.0"
end
gem "rails_template_18f", group: :development, github: "gsa-tts/rails-template"
gem "rails-erd", "~> 1.7", group: :development

group :development, :test do
gem "i18n-tasks", "~> 1.0"
group :development do
gem "rails_template_18f"
gem "rails-erd", "~> 1.7"
end
gem "sidekiq", "~> 7.2"

group :test do
gem "climate_control", "~> 1.0"
gem "shoulda-matchers", "~> 6.2"
gem "oscal", github: "rahearn/oscal-ruby", branch: "allow-setting-logger"
gem "rspec_oscal_formatter", github: "rahearn/rspec_oscal_formatter", branch: "mix-test-types"
gem "byebug", "~> 11.1"
end
50 changes: 42 additions & 8 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
GIT
remote: https://github.com/gsa-tts/rails-template.git
revision: 2c308012e9738725216f7d048e7b43d327d60081
remote: https://github.com/rahearn/oscal-ruby.git
revision: 56faf2931931370acb47e05e7668883c48ffa9ec
branch: allow-setting-logger
specs:
rails_template_18f (1.0.0)
activesupport (~> 7.1.0)
colorize (~> 1.1)
railties (~> 7.1.0)
thor (~> 1.3)
oscal (0.2.1)
yaml

GIT
remote: https://github.com/rahearn/rspec_oscal_formatter.git
revision: 64dbf70748bfde0f9837dd6087f9813caa1c257c
branch: mix-test-types
specs:
rspec_oscal_formatter (0.1.1)
oscal (~> 0.2)
rspec-core (~> 3.13)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -87,6 +94,7 @@ GEM
tzinfo (~> 2.0)
ast (2.4.2)
base64 (0.2.0)
bcrypt (3.1.20)
bigdecimal (3.1.8)
bindex (0.8.1)
bootsnap (1.18.3)
Expand All @@ -97,6 +105,7 @@ GEM
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
byebug (11.1.3)
choice (0.2.0)
climate_control (1.2.0)
colorize (1.1.0)
Expand All @@ -109,6 +118,12 @@ GEM
debug (1.9.2)
irb (~> 1.10)
reline (>= 0.3.8)
devise (4.9.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.5.1)
dotenv (3.1.2)
dotenv-rails (3.1.2)
Expand Down Expand Up @@ -178,6 +193,7 @@ GEM
racc (~> 1.4)
nokogiri (1.16.6-x86_64-linux)
racc (~> 1.4)
orm_adapter (0.5.0)
parallel (1.25.1)
parser (3.3.3.0)
ast (~> 2.4.1)
Expand All @@ -187,6 +203,8 @@ GEM
stringio
puma (6.4.2)
nio4r (~> 2.0)
pundit (2.3.2)
activesupport (>= 3.0.0)
racc (1.8.0)
rack (3.1.4)
rack-session (2.0.0)
Expand Down Expand Up @@ -225,6 +243,11 @@ GEM
rails-i18n (7.0.9)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
rails_template_18f (1.0.0)
activesupport (~> 7.1.0)
colorize (~> 1.1)
railties (~> 7.1.0)
thor (~> 1.3)
railties (7.1.3.4)
actionpack (= 7.1.3.4)
activesupport (= 7.1.3.4)
Expand All @@ -242,6 +265,9 @@ GEM
regexp_parser (2.9.2)
reline (0.5.9)
io-console (~> 0.5)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.3.1)
strscan
rspec-core (3.13.0)
Expand Down Expand Up @@ -316,6 +342,8 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
Expand All @@ -325,6 +353,7 @@ GEM
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
yaml (0.3.0)
zeitwerk (2.6.16)

PLATFORMS
Expand All @@ -339,19 +368,24 @@ DEPENDENCIES
bootsnap
brakeman (~> 6.1)
bundler-audit (~> 0.9)
byebug (~> 11.1)
climate_control (~> 1.0)
cssbundling-rails
debug
devise (~> 4.9)
dotenv-rails (~> 3.1)
i18n-tasks (~> 1.0)
jbuilder
jsbundling-rails
oscal!
pg (~> 1.1)
puma (>= 5.0)
pundit (~> 2.3)
rails (~> 7.1.3, >= 7.1.3.4)
rails-erd (~> 1.7)
rails_template_18f!
rails_template_18f
rspec-rails (~> 6.1)
rspec_oscal_formatter!
secure_headers (~> 6.3)
shoulda-matchers (~> 6.2)
sidekiq (~> 7.2)
Expand Down
15 changes: 1 addition & 14 deletions app/assets/stylesheets/uswds-components.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
@forward "uswds-global";
@forward "uswds-utilities";
@forward "uswds-typography";
@forward "usa-layout-grid";
@forward "usa-header";
@forward "usa-banner";
@forward "usa-section";
@forward "usa-language-selector";
// add additional packages here as you use them
@forward "usa-table";

// or replace these all with
// @forward "uswds";
// to import the entirety of uswds
@forward "uswds";
14 changes: 14 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
class ApplicationController < ActionController::Base
include Pundit::Authorization
after_action :verify_pundit_authorization, unless: :devise_controller?

def verify_pundit_authorization
if action_name == "index"
verify_policy_scoped
else
verify_authorized
end
end

def devise_controller?
self.class.ancestors.include? DeviseController
end
end
77 changes: 77 additions & 0 deletions app/controllers/documents_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
class DocumentsController < ApplicationController
before_action :set_document, only: %i[show edit update destroy]

# GET /documents or /documents.json
def index
@documents = policy_scope(Document)
end

# GET /documents/1 or /documents/1.json
def show
end

# GET /documents/new
def new
@document = Document.new
authorize @document
end

# GET /documents/1/edit
def edit
end

# POST /documents or /documents.json
def create
@document = Document.new(document_params)
authorize @document

respond_to do |format|
if @document.save
logger.info "[PRIVILEGED] Document(#{@document.id}) created by #{current_user.id}"
format.html { redirect_to document_url(@document), notice: "Document was successfully created." }
format.json { render :show, status: :created, location: @document }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @document.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /documents/1 or /documents/1.json
def update
respond_to do |format|
if @document.update(document_params)
logger.info "[PRIVILEGED] Document(#{@document.id}) updated by #{current_user.id}"
format.html { redirect_to document_url(@document), notice: "Document was successfully updated." }
format.json { render :show, status: :ok, location: @document }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @document.errors, status: :unprocessable_entity }
end
end
end

# DELETE /documents/1 or /documents/1.json
def destroy
@document.destroy!
logger.info "[PRIVILEGED] Document(#{@document.id}) destroyed by #{current_user.id}"

respond_to do |format|
format.html { redirect_to documents_url, notice: "Document was successfully destroyed." }
format.json { head :no_content }
end
end

private

# Use callbacks to share common setup or constraints between actions.
def set_document
@document = Document.find(params[:id])
authorize @document
end

# Only allow a list of trusted parameters through.
def document_params
params.fetch(:document, {}).permit :url, :title, :description
end
end
3 changes: 2 additions & 1 deletion app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class PagesController < ApplicationController
def home
@documents = Document.all
skip_authorization # skip the authorization check because we're using policy_scope here.
@documents = policy_scope(Document)
end
end
9 changes: 9 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,13 @@ def active_locale?(locale_string)
def language_span(locale_string)
content_tag :span, t("shared.languages.#{locale_string}"), lang: locale_string, "xml:lang": locale_string
end

def external_link(text, url = nil)
url ||= text
link_to text, url, class: "usa-link usa-link--external", rel: "noreferrer", target: "_blank"
end

def required_field_label(field_name)
"#{field_name}<abbr title=\"required\" class=\"usa-hint usa-hint--required\">*</abbr>".html_safe
end
end
2 changes: 1 addition & 1 deletion app/models/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Document < ApplicationRecord
def url_is_https
parsed = URI(url)
errors.add(:url, "must begin with https") unless parsed.scheme == "https"
rescue ArgumentError
rescue ArgumentError, URI::InvalidURIError
errors.add(:url, "must begin with https")
end
end
6 changes: 6 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:rememberable, :validatable, :lockable
end
53 changes: 53 additions & 0 deletions app/policies/application_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

class ApplicationPolicy
attr_reader :user, :record

def initialize(user, record)
@user = user
@record = record
end

def index?
false
end

def show?
false
end

def create?
false
end

def new?
create?
end

def update?
false
end

def edit?
update?
end

def destroy?
false
end

class Scope
def initialize(user, scope)
@user = user
@scope = scope
end

def resolve
raise NoMethodError, "You must define #resolve in #{self.class}"
end

private

attr_reader :user, :scope
end
end
Loading