diff --git a/Gemfile b/Gemfile
index 2c95dd400..40b38f8a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -25,6 +25,7 @@ gem 'doorkeeper', '>= 4.6'
gem 'omniauth'
gem 'omniauth-azure-activedirectory'
gem 'omniauth-linkedin-oauth2'
+gem 'omniauth-okta'
# TODO: remove this when omniauth gem resolves CVE issues
# Prevents CVE-2015-9284 (https://github.com/omniauth/omniauth/wiki/FAQ#cve-2015-9284-warnings)
diff --git a/Gemfile.lock b/Gemfile.lock
index 9b0fe960b..84668d848 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -407,6 +407,9 @@ GEM
omniauth-oauth2 (1.7.1)
oauth2 (~> 1.4)
omniauth (>= 1.9, < 3)
+ omniauth-okta (0.1.3)
+ omniauth (~> 1.5)
+ omniauth-oauth2 (>= 1.6.0, < 2.0)
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
@@ -692,6 +695,7 @@ DEPENDENCIES
omniauth
omniauth-azure-activedirectory
omniauth-linkedin-oauth2
+ omniauth-okta
omniauth-rails_csrf_protection (~> 0.1)
overcommit
pg (~> 1.1)
diff --git a/app/assets/stylesheets/themes/scinote.scss b/app/assets/stylesheets/themes/scinote.scss
index 75d800949..49efda8e5 100644
--- a/app/assets/stylesheets/themes/scinote.scss
+++ b/app/assets/stylesheets/themes/scinote.scss
@@ -401,6 +401,16 @@ a[data-toggle="tooltip"] {
}
}
+.okta-sign-in-actions {
+ margin-bottom: 10px;
+ margin-top: 10px;
+
+ .btn-okta {
+ background-color: #00297a;
+ color: $color-white;
+ }
+}
+
.navbar-secondary {
transition: .4s $timing-function-sharp;
}
diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb
index c1f963cfb..e4c56921e 100644
--- a/app/controllers/users/omniauth_callbacks_controller.rb
+++ b/app/controllers/users/omniauth_callbacks_controller.rb
@@ -127,11 +127,50 @@ module Users
redirect_to after_omniauth_failure_path_for(resource_name) and return
end
# Confirm user
- @user.update_column(:confirmed_at, @user.created_at)
+ @user.update!(confirmed_at: @user.created_at)
redirect_to users_sign_up_provider_path(user: @user)
end
end
+ def okta
+ auth = request.env['omniauth.auth']
+ user = User.from_omniauth(auth)
+ # User found in database so just signing in
+ return sign_in_and_redirect(user) if user.present?
+
+ user = User.find_by(email: auth.info.email.downcase)
+
+ if user.blank?
+ # Create new user and identity
+ user = User.new(full_name: auth.info.name,
+ initials: generate_initials(auth.info.name),
+ email: auth.info.email,
+ password: generate_user_password)
+ User.transaction do
+ user.save!
+ user.user_identities.create!(provider: auth.provider, uid: auth.uid)
+ user.update!(confirmed_at: user.created_at)
+ end
+ else
+ # Link to existing local account
+ user.user_identities.create!(provider: auth.provider, uid: auth.uid)
+ user.update!(confirmed_at: user.created_at) if user.confirmed_at.blank?
+ end
+ sign_in_and_redirect(user)
+ rescue StandardError => e
+ Rails.logger.error e.message
+ Rails.logger.error e.backtrace.join("\n")
+ error_message = I18n.t('devise.okta.errors.failed_to_save') if e.is_a?(ActiveRecord::RecordInvalid)
+ error_message ||= I18n.t('devise.okta.errors.generic')
+ redirect_to after_omniauth_failure_path_for(resource_name)
+ ensure
+ if error_message
+ set_flash_message(:alert, :failure, kind: I18n.t('devise.okta.provider_name'), reason: error_message)
+ else
+ set_flash_message(:notice, :success, kind: I18n.t('devise.okta.provider_name'))
+ end
+ end
+
# More info at:
# https://github.com/plataformatec/devise#omniauth
diff --git a/app/views/users/shared/_links.html.erb b/app/views/users/shared/_links.html.erb
index 1d520d0f6..2e796a990 100644
--- a/app/views/users/shared/_links.html.erb
+++ b/app/views/users/shared/_links.html.erb
@@ -25,6 +25,14 @@
<% end -%>
+ <%- if devise_mapping.omniauthable? && Devise.omniauth_configs[:okta].present? %>
+
+ <%= form_tag omniauth_authorize_path(resource_name, :okta), method: :post do %>
+ <%= submit_tag t('devise.okta.sign_in_label'), class: 'btn btn-okta' %>
+ <% end %>
+
+ <% end %>
+
<%- unless defined?(linkedin_skip) %>
<%- if Rails.configuration.x.enable_user_registration && Rails.configuration.x.linkedin_signin_enabled && @oauth_authorize != true %>
<%= render partial: "users/shared/linkedin_sign_in_links", locals: { resource_name: resource_name } %>
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index b75ab2b81..4ffc10175 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -295,6 +295,23 @@ Devise.setup do |config|
config.omniauth :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET'], scope: 'r_liteprofile r_emailaddress'
end
+ if [ENV['OKTA_CLIENT_ID'], ENV['OKTA_CLIENT_SECRET'], ENV['OKTA_DOMAIN'], ENV['OKTA_AUTH_SERVER_ID']].all?
+ config.omniauth(
+ :okta,
+ ENV['OKTA_CLIENT_ID'],
+ ENV['OKTA_CLIENT_SECRET'],
+ scope: 'openid profile email',
+ fields: %w(profile email),
+ client_options: {
+ site: "https://#{ENV['OKTA_DOMAIN']}",
+ authorize_url: "https://#{ENV['OKTA_DOMAIN']}/oauth2/#{ENV['OKTA_AUTH_SERVER_ID']}/v1/authorize",
+ token_url: "https://#{ENV['OKTA_DOMAIN']}/oauth2/#{ENV['OKTA_AUTH_SERVER_ID']}/v1/token",
+ user_info_url: "https://#{ENV['OKTA_DOMAIN']}/oauth2/#{ENV['OKTA_AUTH_SERVER_ID']}/v1/userinfo"
+ },
+ strategy_class: OmniAuth::Strategies::Okta
+ )
+ end
+
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
# change the failure app, you can configure them inside the config.warden block.
diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb
index bc9c14a62..e48fceb99 100644
--- a/config/initializers/extends.rb
+++ b/config/initializers/extends.rb
@@ -1,6 +1,8 @@
# Extends class holds the arrays for the models enum fields
# so that can be extended in sub modules.
+# rubocop:disable Style/MutableConstant
+
class Extends
# To extend the enum fields in the engine you have to put in
# lib/engine_name/engine.rb file as in the example:
@@ -109,7 +111,7 @@ class Extends
'RepositoryAssetValue' => 'file',
'RepositoryStatusValue' => 'status' }
- OMNIAUTH_PROVIDERS = [:linkedin, :customazureactivedirectory]
+ OMNIAUTH_PROVIDERS = %i(linkedin customazureactivedirectory okta)
INITIAL_USER_OPTIONS = {}
@@ -395,3 +397,5 @@ class Extends
change_user_role_on_my_module
)
end
+
+# rubocop:enable Style/MutableConstant
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
index e216bdb89..233f74eb4 100644
--- a/config/initializers/omniauth.rb
+++ b/config/initializers/omniauth.rb
@@ -2,7 +2,7 @@
require 'omniauth/strategies/custom_azure_active_directory'
-SETUP_PROC = lambda do |env|
+AZURE_SETUP_PROC = lambda do |env|
providers = Rails.configuration.x.azure_ad_apps.select { |_, v| v[:enable_sign_in] == true }
raise StandardError, 'No Azure AD config available for sign in' if providers.blank?
@@ -31,7 +31,7 @@ SETUP_PROC = lambda do |env|
end
Rails.application.config.middleware.use OmniAuth::Builder do
- provider OmniAuth::Strategies::CustomAzureActiveDirectory, setup: SETUP_PROC
+ provider OmniAuth::Strategies::CustomAzureActiveDirectory, setup: AZURE_SETUP_PROC
end
OmniAuth.config.logger = Rails.logger
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 49116c754..98752f257 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -74,6 +74,13 @@ en:
no_local_user_map: "No local user record found"
no_email: "Email is missing in auth token"
failed_to_save: "Failed to create new user"
+ okta:
+ provider_name: "Okta"
+ sign_in_label: "Sign in with Okta"
+ errors:
+ generic: "Failed to sign in user"
+ no_local_user_map: "No local user record found"
+ failed_to_save: "Failed to create new user"
doorkeeper:
errors: