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

Add sso integration with keycloak #612

Merged
merged 67 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
2bba9a6
add auth gem
kcinay055679 Feb 23, 2024
1a7a935
openid-connect
kcinay055679 Feb 23, 2024
eb7c8e5
add devse
kcinay055679 Feb 26, 2024
5c92a28
remove key from file
kcinay055679 Feb 26, 2024
9585498
add rubocop
kcinay055679 Feb 26, 2024
f787754
fixx gemfile
kcinay055679 Feb 26, 2024
a3fc7b4
fix gemfile
kcinay055679 Feb 26, 2024
81860e9
add openid and devise
kcinay055679 Feb 26, 2024
bfa0042
setup devise with openid_connect
kcinay055679 Feb 26, 2024
d75cc7e
login works
kcinay055679 Feb 26, 2024
71ca3a4
remove openid_connect gem
kcinay055679 Feb 26, 2024
fb3a303
first steps to add before action
kcinay055679 Feb 26, 2024
c85fb95
remove useless controller
kcinay055679 Feb 27, 2024
987f782
setup omniauth as only provider
kcinay055679 Feb 27, 2024
c74916a
prepare to add custom views
kcinay055679 Feb 27, 2024
dad8052
add callback controler
kcinay055679 Feb 27, 2024
5ff152a
auth works
kcinay055679 Feb 27, 2024
daa7aad
clean up pr
kcinay055679 Feb 27, 2024
a6243fe
clean up
kcinay055679 Feb 27, 2024
9e3e0b6
clean up
kcinay055679 Feb 27, 2024
dcc0f3d
clean up
kcinay055679 Feb 27, 2024
d0a12ab
fix controller
kcinay055679 Feb 27, 2024
a38759c
update callback controller
kcinay055679 Feb 29, 2024
8ffdfc5
fix auth for tests
kcinay055679 Feb 29, 2024
0b88021
add column for is_admin
kcinay055679 Feb 29, 2024
71de7fc
prepare to change omniauth lib
kcinay055679 Feb 29, 2024
5304e6e
clean up
kcinay055679 Feb 29, 2024
4211e81
test keycloak plugin
kcinay055679 Feb 29, 2024
581bb40
fix config of new plugin
kcinay055679 Feb 29, 2024
c2d3292
use keycloak_openid plugin with correct config
kcinay055679 Feb 29, 2024
3aed5d2
implement admin check
kcinay055679 Feb 29, 2024
f2f125e
add permission check
kcinay055679 Feb 29, 2024
012289f
use auth config file to manage auth configs
kcinay055679 Feb 29, 2024
a2a1a3f
setup compatibility for openshift
kcinay055679 Feb 29, 2024
6e96e48
fix api tests
kcinay055679 Feb 29, 2024
b1b96fd
clean up pr
kcinay055679 Mar 1, 2024
f311710
render unauthorized error
kcinay055679 Mar 1, 2024
151ad9f
show omniauth provider buttons only
kcinay055679 Mar 1, 2024
2a47618
set admin on login
kcinay055679 Mar 1, 2024
43c494a
fix visuals
kcinay055679 Mar 1, 2024
48be77f
skip before action only for keycloak openid
kcinay055679 Mar 1, 2024
29f2c4b
restore rubocop config
kcinay055679 Mar 1, 2024
1b4fb60
make rubocop happy
kcinay055679 Mar 1, 2024
dfae7be
remove secret
kcinay055679 Mar 1, 2024
b20445b
add auth.yml file without secret
kcinay055679 Mar 1, 2024
298ca4f
update gitignore
kcinay055679 Mar 1, 2024
ff35a52
restore gitignore
kcinay055679 Mar 1, 2024
da7f912
setup new model
kcinay055679 Mar 1, 2024
8ad5780
update migration
kcinay055679 Mar 1, 2024
4b15c43
clean up
kcinay055679 Mar 1, 2024
5a0a081
fix tests
kcinay055679 Mar 1, 2024
a1be334
fix tests
kcinay055679 Mar 1, 2024
4c47799
trigger checks
kcinay055679 Mar 1, 2024
ef73c8b
fix implementation of get_var_from_env method
kcinay055679 Mar 4, 2024
9d5d6ee
update security config
kcinay055679 Mar 4, 2024
fc71527
add dotenv gem
kcinay055679 Mar 5, 2024
2cce093
setup default user for development
kcinay055679 Mar 5, 2024
17bb6c4
hide login and logout for development
kcinay055679 Mar 5, 2024
6712814
rename helper
kcinay055679 Mar 5, 2024
a758cba
clena up
kcinay055679 Mar 5, 2024
a622806
render errors dynamic
kcinay055679 Mar 5, 2024
a125570
add auth tests
kcinay055679 Mar 5, 2024
4b4e184
update read me
kcinay055679 Mar 5, 2024
4bc6513
use error_modal to render errors
kcinay055679 Mar 5, 2024
113ecd6
Add tests to check if user can create new skill
kcinay055679 Mar 5, 2024
c5c4ad8
clean up
kcinay055679 Mar 5, 2024
6b8bd2c
Make ENV variable fetching work and more standardized
Robin481 Mar 12, 2024
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: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LOCAL=true
DEVELOPMENT=true
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem 'config'
gem 'countries'
gem 'cssbundling-rails'
gem 'database_cleaner'
gem 'devise'
gem 'faker'
gem 'haml-rails'
gem 'i18n_data'
Expand All @@ -28,6 +29,8 @@ gem 'net-pop', require: false
gem 'net-smtp', require: false
gem 'nokogiri', '~> 1.14'
gem 'odf-report'
gem 'omniauth-keycloak'
gem 'omniauth-rails_csrf_protection'
gem 'pg'
gem 'pg_search'
gem 'psych', '~> 3.3', '>= 3.3.4'
Expand All @@ -51,6 +54,7 @@ group :development, :test do
# Call 'byebug' anywhere in the code
# to stop execution and get a debugger console
gem 'byebug', platform: :mri
gem 'dotenv'
gem 'pry'
gem 'pry-byebug'
gem 'rspec-rails'
Expand Down
53 changes: 52 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ GEM
rake (>= 10.4, < 14.0)
ast (2.4.2)
base64 (0.2.0)
bcrypt (3.1.20)
bigdecimal (3.1.6)
bindata (2.5.0)
bleib (0.0.8)
Expand Down Expand Up @@ -130,9 +131,16 @@ GEM
database_cleaner-core (2.0.1)
date (3.3.4)
deep_merge (1.2.2)
devise (4.9.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.5.1)
docile (1.4.0)
domain_name (0.6.20240107)
dotenv (3.1.0)
dry-configurable (1.1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
Expand Down Expand Up @@ -187,6 +195,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
hashie (5.0.0)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
Expand All @@ -208,6 +217,8 @@ GEM
faraday (~> 2.0)
faraday-follow_redirects
jsonapi-renderer (0.2.2)
jwt (2.8.0)
base64
keycloak-api-rails (0.12.2)
json-jwt (>= 1.11.0)
rails (>= 4.2)
Expand Down Expand Up @@ -237,6 +248,7 @@ GEM
mini_mime (1.1.5)
minitest (5.22.2)
msgpack (1.7.2)
multi_xml (0.6.0)
net-http (0.4.1)
uri
net-imap (0.4.10)
Expand All @@ -253,10 +265,33 @@ GEM
nio4r (2.7.0)
nokogiri (1.16.2-x86_64-linux)
racc (~> 1.4)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
odf-report (0.7.3)
mime-types
nokogiri (>= 1.10.0)
rubyzip (>= 1.3.0)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-keycloak (1.5.2)
faraday
json-jwt (> 1.13.0)
omniauth (>= 2.0)
omniauth-oauth2 (>= 1.7, < 1.9)
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
orm_adapter (0.5.0)
parallel (1.24.0)
parser (3.3.0.5)
ast (~> 2.4.1)
Expand All @@ -277,6 +312,9 @@ GEM
nio4r (~> 2.0)
racc (1.7.3)
rack (2.2.8.1)
rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rack-test (2.1.0)
rack (>= 1.3)
rails (7.0.4.2)
Expand Down Expand Up @@ -322,6 +360,9 @@ GEM
ffi (~> 1.0)
rb-readline (0.5.5)
regexp_parser (2.9.0)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
Expand All @@ -344,7 +385,7 @@ GEM
rspec-expectations (~> 3.12)
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-support (3.13.0)
rspec-support (3.13.1)
rubocop (1.60.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
Expand Down Expand Up @@ -385,6 +426,9 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
spring (2.1.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
Expand Down Expand Up @@ -413,6 +457,9 @@ GEM
unicode-display_width (2.5.0)
uniform_notifier (1.16.0)
uri (0.13.0)
version_gem (1.1.3)
warden (1.2.9)
rack (>= 2.0.9)
webdrivers (5.3.1)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
Expand Down Expand Up @@ -443,6 +490,8 @@ DEPENDENCIES
countries
cssbundling-rails
database_cleaner
devise
dotenv
faker
haml-rails
i18n_data
Expand All @@ -458,6 +507,8 @@ DEPENDENCIES
net-smtp
nokogiri (~> 1.14)
odf-report
omniauth-keycloak
omniauth-rails_csrf_protection
pg
pg_search
pry
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ You will need the following things properly installed on your computer:
## Setup dockerized Application👩🏽‍💻
We're glad you want to setup your machine for PuzzleSkills development 💃

## Openshift deployment
To deploy the project to openshift make sure you set the following environment variables:
- LOCAL=false
- client_id:
- secret:
- host_url:
- realm:
- admin_role: (Not required)


### Windows users
If you're on Windows you should be able to Download Ubuntu from Microsoft Store. Note that you need to enable Subsystem for Linux and virtual machine platform in your Windows features.
Then you can open Ubuntu and follow the manual using the Ubuntu console.
Expand Down Expand Up @@ -91,6 +101,7 @@ Access the web application by browser: http://localhost:4200 and enjoy the ride!
- Frontend tests with livereload `rake spec:frontend:serve`
- To run a single test run the following command in the frontend folder `npm test --filter "some filter words"`
- There is also `rake ci` and `rake ci:nightly` which should be periodically exectued by a build job (e.g. on jenkins)
- To use a user without admin privileges change email in `app/controllers/application_controller.rb#authenticate_auth_user"` to "[email protected]"


## Documentation
Expand Down
Binary file added app/assets/images/profil.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
# frozen_string_literal: true

class ApplicationController < ActionController::Base
before_action :authenticate_auth_user!

def authenticate_auth_user!
return super unless helpers.development?

admin = AuthUser.find_by(email: '[email protected]')
request.env['warden'].set_user(admin, :scope => :auth_user)
end

def render_unauthorized
return false if helpers.admin?
kcinay055679 marked this conversation as resolved.
Show resolved Hide resolved

render_error('unauthorized', 'unauthorized', :unauthorized)
end

def render_error(title_key, body_key, status = :bad_request)
render partial: 'error_modal',
locals: { title: translate("devise.failure.titles.#{title_key}"),
body: translate("devise.failure.#{body_key}") },
:status => status
end
end
20 changes: 20 additions & 0 deletions app/controllers/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token, only: :keycloak_openid

def keycloak_openid
omniauth_auth = request.env['omniauth.auth']
@user = AuthUser.from_omniauth(omniauth_auth)
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: 'Keycloak') if is_navigational_format?
else
failure
end
end

def failure
redirect_to root_path
end
end
5 changes: 1 addition & 4 deletions app/controllers/skills_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# frozen_string_literal: true

require 'keycloak_tools'

class SkillsController < CrudController
include ExportController
include KeycloakTools

before_action :authorize_admin, except: %i[index show create unrated_by_person]
before_action :render_unauthorized, except: %i[index show unrated_by_person]

self.permitted_attrs = %i[title radar portfolio default_set category_id]

Expand Down
21 changes: 21 additions & 0 deletions app/helpers/auth_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module AuthHelper
def session_path(_scope)
new_auth_user_session_path
end

def admin?
current_auth_user&.is_admin
end

def generate_select_options_with_default(person)
selected = person ? person.id : ''
prompt = person ? false : true
{ :selected => selected, :prompt => prompt, :disabled => '' }
end

def development?
ENV['DEVELOPMENT'] == 'true' && ENV['RAILS_ENV'] == 'development'
end
end
30 changes: 30 additions & 0 deletions app/models/auth_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

class AuthUser < ApplicationRecord

devise :omniauthable, omniauth_providers: [:keycloak_openid]

class << self
def from_omniauth(auth)
person = where(uid: auth.uid).first_or_create do |user|
user.name = auth.info.name
user.email = auth.info.email
end
person.last_login = Time.zone.now
set_admin(person, auth)
end

private

def set_admin(person, auth)
person.is_admin = admin?(auth)
person.save
person
end

def admin?(auth)
resources = auth.extra.raw_info.resource_access[AuthConfig.client_id]
resources.roles.include? AuthConfig.admin_role
end
end
end
2 changes: 2 additions & 0 deletions app/views/application/_error_modal.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
= render "remote_modal", title: title do
= body
6 changes: 6 additions & 0 deletions app/views/devise/sessions/new.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%h2 Log in
- if devise_mapping.omniauthable?
- resource_class.omniauth_providers.each do |provider|
= button_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), {data: { turbo: false }, class: "btn btn-primary"}
- else
An error %occured, no Omniauth providers are available, please contact the administrator.
11 changes: 9 additions & 2 deletions app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
%ul.navbar.text-gray
%li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100
%pzsh-icon.scale-icon-06(name="user")
%text= "Curtis Jackson"
%span#username
=current_auth_user&.name
- if admin?
(Admin)
%li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2
%a.d-flex.align-items-center{:href => "https://github.com/puzzle/skills/issues"}
%pzsh-icon.scale-icon-08.text-gray(name="question-circle")
%li.d-flex.align-items-center.cursor-pointer.border-start.border-end.h-100.ps-2.pe-2
%a= "Logout"
- if !development?
- if auth_user_signed_in?
=link_to "Logout", destroy_auth_user_session_path, data: { "turbo-method": :delete}
- elsif devise_mapping.omniauthable?
=button_to "Login", omniauth_authorize_path(resource_name, resource_class.omniauth_providers.first), {data: { "turbo": false}, class: "btn btn-link"}
%div
%pzsh-topbar.p-0
%div.d-flex.justify-content-center
Expand Down
2 changes: 1 addition & 1 deletion app/views/people/_search.html.haml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
= form_with do |f|
%section{"data-controller"=>"dropdown"}
= f.collection_select :person_id, Person.all.sort_by(&:name), :id, :name, {:selected => person&.id} , {class: "form-select w-100", "data-action": "change->dropdown#handleChange", "data-value": "/people/"}
= f.collection_select :person_id, Person.all.sort_by(&:name), :id, :name, generate_select_options_with_default(person) , {class: "form-select w-100", "data-action": "change->dropdown#handleChange", "data-value": "/people/"}
2 changes: 1 addition & 1 deletion app/views/people/index.html.haml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
= render partial: "people/search", locals: { person: @people.order(:name).first }
= render partial: "people/search", locals: { person: nil }
2 changes: 1 addition & 1 deletion app/views/skills/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
%td= skill.title
%td.table-light= skill.people.count
%td= skill.category.title
%td.table-light= skill.category.parent.title
%td.table-light= skill.category.parent&.title
%td= skill.default_set.nil? ? "Neu" : (skill.default_set? ? "Ja" : "Nein")
%td.table-light= skill.radar
%td
Expand Down
5 changes: 5 additions & 0 deletions config/auth.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
client_id: pitc_skills_rails_backend
secret:
host_url: https://sso-test.puzzle.ch
realm: pitc
admin_role: ADMIN
4 changes: 3 additions & 1 deletion config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

config.action_mailer.perform_caching = false

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log

Expand All @@ -57,7 +59,7 @@
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker

# Bullet configuration
# Bullet configuration
config.after_initialize do
Bullet.enable = true

Expand Down
Loading