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

[22 | 24] Users can login/logout via Rails app #101

Merged
merged 13 commits into from
Aug 9, 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
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@ group :test do
gem "capybara"
gem "selenium-webdriver"
gem "rspec_junit_formatter"
gem "simplecov"
gem 'simplecov', '~> 0.17.0', require: false
gem "rails-controller-testing"
end
56 changes: 30 additions & 26 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ GEM
base64 (0.2.0)
bigdecimal (3.1.8)
bindex (0.8.1)
bootsnap (1.18.3)
bootsnap (1.18.4)
msgpack (~> 1.2)
builder (3.3.0)
capybara (3.40.0)
Expand All @@ -96,8 +96,8 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
codeclimate-test-reporter (1.0.9)
simplecov (<= 0.13)
codeclimate-test-reporter (1.0.7)
simplecov
concurrent-ruby (1.3.3)
connection_pool (2.4.1)
crack (1.0.0)
Expand All @@ -111,18 +111,18 @@ GEM
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.5.1)
docile (1.1.5)
docile (1.4.1)
drb (2.2.1)
erubi (1.13.0)
faraday (2.10.0)
faraday (2.10.1)
faraday-net_http (>= 2.0, < 3.2)
logger
faraday-net_http (3.1.0)
faraday-net_http (3.1.1)
net-http
foreman (0.88.1)
globalid (1.2.1)
activesupport (>= 6.1)
hashdiff (1.1.0)
hashdiff (1.1.1)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
Expand Down Expand Up @@ -165,19 +165,23 @@ GEM
net-smtp (0.5.0)
net-protocol
nio4r (2.7.3)
nokogiri (1.16.6-aarch64-linux)
nokogiri (1.16.7-aarch64-linux)
racc (~> 1.4)
nokogiri (1.16.6-arm64-darwin)
nokogiri (1.16.7-arm-linux)
racc (~> 1.4)
nokogiri (1.16.6-x86_64-darwin)
nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.6-x86_64-linux)
nokogiri (1.16.7-x86-linux)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
parallel (1.25.1)
parser (3.3.4.0)
ast (~> 2.4.1)
racc
pg (1.5.6)
pg (1.5.7)
prism (0.30.0)
propshaft (0.9.0)
actionpack (>= 7.0.0)
Expand All @@ -186,7 +190,7 @@ GEM
railties (>= 7.0.0)
psych (5.1.2)
stringio
public_suffix (6.0.0)
public_suffix (6.0.1)
puma (6.4.2)
nio4r (~> 2.0)
racc (1.8.1)
Expand Down Expand Up @@ -272,7 +276,7 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
rubocop-ast (1.32.0)
parser (>= 3.3.1.0)
rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0)
Expand All @@ -284,9 +288,9 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rake (0.6.0)
rubocop (~> 1.0)
rubocop-rspec (3.0.3)
rubocop-rspec (3.0.4)
rubocop (~> 1.61)
ruby-lsp (0.17.9)
ruby-lsp (0.17.11)
language_server-protocol (~> 3.17.0)
prism (>= 0.29.0, < 0.31)
rbs (>= 3, < 4)
Expand All @@ -299,12 +303,12 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
simplecov (0.13.0)
docile (~> 1.1.0)
simplecov (0.17.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
sorbet-runtime (0.5.11492)
sorbet-runtime (0.5.11511)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
stringio (3.1.1)
Expand Down Expand Up @@ -335,14 +339,14 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.16)
zeitwerk (2.6.17)

PLATFORMS
aarch64-linux
arm64-darwin-21
arm64-darwin-22
arm64-darwin-23
x86_64-darwin-22
arm-linux
arm64-darwin
x86-linux
x86_64-darwin
x86_64-linux

DEPENDENCIES
Expand Down Expand Up @@ -371,7 +375,7 @@ DEPENDENCIES
rubocop-rspec
ruby-lsp
selenium-webdriver
simplecov
simplecov (~> 0.17.0)
stimulus-rails
turbo-rails
tzinfo-data
Expand All @@ -382,4 +386,4 @@ RUBY VERSION
ruby 3.2.4p170

BUNDLED WITH
2.4.6
2.5.9
10 changes: 7 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ Rails.application.load_tasks

namespace :cf do
desc "Only run on the first application instance"
task :on_first_instance do
instance_index = JSON.parse(ENV["VCAP_APPLICATION"])["instance_index"] rescue nil
exit(0) unless instance_index == 0
task on_first_instance: :environment do
instance_index = begin
JSON.parse(ENV.fetch("VCAP_APPLICATION", nil))["instance_index"]
rescue
nil
end
exit(0) unless instance_index.zero?
end
end
30 changes: 30 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@
# frozen_string_literal: true

class ApplicationController < ActionController::Base
helper_method :current_user, :logged_in?

def current_user
return unless session[:userinfo]

user_token = session["userinfo"][0]["sub"]
@current_user ||= User.find_by(token: user_token) if user_token
end

def logged_in?
!!current_user
end

def sign_in(login_userinfo)
user = User.user_from_userinfo(login_userinfo)

@current_user = user
session[:userinfo] = login_userinfo
end

def sign_out
@current_user = nil
session.delete(:userinfo)
end

def redirect_if_logged_in(path = "/dashboard")
return unless logged_in?

redirect_to path, notice: I18n.t("already_logged_in_notice")
end
end
5 changes: 5 additions & 0 deletions app/controllers/dashboard_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class DashboardController < ApplicationController
def index; end
end
11 changes: 5 additions & 6 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@ def create
redirect_to(login_gov.authorization_url, allow_other_host: true)
end

def delete
def destroy
login_gov = LoginGov.new
# TODO: update user session status, clear out JWT
# TODO: add session duration to the security log
# TODO: delete session locally and Phoenix
redirect_to(login_gov.logout_url)
sign_out
redirect_to(login_gov.logout_url, allow_other_host: true)
end

def result
# TODO: store the user_info in the session
# session[:user_info] = @login_userinfo
sign_in(@login_userinfo)
redirect_to dashboard_path
end

private
Expand Down
10 changes: 10 additions & 0 deletions app/models/application_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@

class ApplicationRecord < ActiveRecord::Base
primary_abstract_class

attribute :inserted_at, :datetime, precision: 6
attribute :updated_at, :datetime, precision: 6

# created_at timestamp is currently overridden to inserted_at due to shared Phoenix database
def self.timestamp_attributes_for_create
# only strings allowed here, symbols won't work, see below commit for more details
# https://github.com/rails/rails/commit/2b5dacb43dd92e98e1fd240a80c2a540ed380257
super << 'inserted_at'
end
Comment on lines +10 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤘

end
52 changes: 50 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,55 @@ class User < ApplicationRecord

attribute :renewal_request, :string

attribute :updated_at, :datetime, precision: 6

validates :email, presence: true

# Finds, creates, or updates user from userinfo
# Find in case of user with existing token matching userinfo["sub"]
# Create in case of no token or email matching in userinfo
# Update in case of matching email to userinfo["email"] but no token set
# TODO: Add relevant security log tracking here?
def self.user_from_userinfo(userinfo)
email = userinfo[0]["email"]
token = userinfo[0]["sub"]

if (user = find_by(token:))
user
elsif (user = find_by(email:))
update_admin_added_user(user, userinfo)
stepchud marked this conversation as resolved.
Show resolved Hide resolved
else
create_user_from_userinfo(userinfo)
end
end

def self.update_admin_added_user(user, userinfo)
update(user.id, { token: userinfo[0]["sub"] })
end

def self.create_user_from_userinfo(userinfo)
email = userinfo[0]["email"]
token = userinfo[0]["sub"]

default_role, default_status = default_role_and_status_for_email(email)

create({
email:,
role: default_role,
token:,
terms_of_use: nil,
privacy_guidelines: nil,
status: default_status
})
end

def self.default_role_and_status_for_email(email)
if default_challenge_manager?(email)
%w[challenge_manager pending]
else
%w[solver active]
end
end

def self.default_challenge_manager?(email)
/\.(gov|mil)$/.match?(email)
end
end
9 changes: 9 additions & 0 deletions app/views/dashboard/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="usa-card__container custom-card col-md-6 rules-of-behavior">
<div class="usa-card__body">
<% if logged_in? %>
Logged In Dashboard Index
<% else %>
Logged Out Dashboard Index
<% end %>
</div>
</div>
18 changes: 18 additions & 0 deletions app/views/layouts/_header.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<header class="usa-header usa-header--basic margin-bottom-2">
<div class="usa-nav-container">
<div class="usa-navbar">
<div class="usa-logo">
<em class="usa-logo__text">
<a href="/" title="Challenge Platform">Challenge Platform</a>
</em>
</div>
</div>
<nav aria-label="Primary navigation" class="usa-nav">
<% if logged_in? %>
<%= button_to("Logout", session_path, method: :delete, class: "usa-button usa-nav-link", type: "button") %>
<% else %>
<%= button_to("Login", new_session_path, method: :get, class: "usa-button usa-nav-link", type: "button") %>
<% end %>
</nav>
</div>
</header>
1 change: 1 addition & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</head>

<body>
<%= render "layouts/header" %>
<%= yield %>
</body>
</html>
2 changes: 1 addition & 1 deletion config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@

# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true
end
end
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ en:
hello: "Hello world"
please_try_again: "Please try again."
login_error: "There was an issue with logging in. Please try again."
already_logged_in_notice: "You are already logged in."
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
get 'auth/result', to: 'sessions#result'
resource 'session', only: [:new, :create, :destroy]

get '/', to: "dashboard#index"
get '/dashboard', to: "dashboard#index"

# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
# Can be used by load balancers and uptime monitors to verify that the app is live.
get "up" => "rails/health#show", as: :rails_health_check
Expand Down
Loading
Loading