mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-01-30 11:41:19 +08:00
Move Okta and Azure AD configurations to application settings [SCI-7609] (#4732)
This commit is contained in:
parent
4439d044ab
commit
e1c4aa9469
9 changed files with 115 additions and 112 deletions
|
@ -18,10 +18,11 @@ module Users
|
|||
def customazureactivedirectory
|
||||
auth = request.env['omniauth.auth']
|
||||
provider_id = auth.dig(:extra, :raw_info, :aud)
|
||||
provider_conf = Rails.configuration.x.azure_ad_apps[provider_id]
|
||||
settings = ApplicationSettings.instance
|
||||
provider_conf = settings.values['azure_ad_apps'].find { |v| v['enable_sign_in'] && v['app_id'] == provider_id }
|
||||
raise StandardError, 'No matching Azure AD provider config found' if provider_conf.blank?
|
||||
|
||||
auth.provider = provider_conf[:provider]
|
||||
auth.provider = provider_conf['provider_name']
|
||||
|
||||
return redirect_to connected_accounts_path if current_user
|
||||
|
||||
|
|
|
@ -219,6 +219,14 @@ module ApplicationHelper
|
|||
'icon_small/missing.png'
|
||||
end
|
||||
|
||||
def okta_configured?
|
||||
ApplicationSettings.instance.values['okta'].present?
|
||||
end
|
||||
|
||||
def azure_ad_configured?
|
||||
ApplicationSettings.instance.values['azure_ad_apps'].present?
|
||||
end
|
||||
|
||||
def wopi_enabled?
|
||||
ENV['WOPI_ENABLED'] == 'true'
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<% Rails.configuration.x.azure_ad_apps.select { |uid, config| config[:enable_sign_in] }.each do |uid, config| %>
|
||||
<% ApplicationSettings.instance.values['azure_ad_apps'].select { |v| v['enable_sign_in'] }.each do |config| %>
|
||||
<div class="form-group">
|
||||
<%= form_tag user_customazureactivedirectory_omniauth_authorize_path(provider: config[:provider]), method: :post do %>
|
||||
<%= submit_tag config[:sign_in_label], class: 'btn btn-azure-ad' %>
|
||||
<%= form_tag user_customazureactivedirectory_omniauth_authorize_path(provider: config['provider']), method: :post do %>
|
||||
<%= submit_tag config['sign_in_label'] || t('devise.sessions.new.azure_ad_submit'), class: 'btn btn-azure-ad' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<div data-hook="omniauth-sign-in-links"></div>
|
||||
<% end -%>
|
||||
|
||||
<%- if devise_mapping.omniauthable? && Devise.omniauth_configs[:okta].present? %>
|
||||
<%- if devise_mapping.omniauthable? && okta_configured? %>
|
||||
<div class="okta-sign-in-actions">
|
||||
<%= form_tag omniauth_authorize_path(resource_name, :okta), method: :post do %>
|
||||
<%= submit_tag t('devise.okta.sign_in_label'), class: 'btn btn-okta' %>
|
||||
|
@ -41,7 +41,9 @@
|
|||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
<div class="azure-sign-in-actions">
|
||||
<%= render partial: "users/shared/azure_sign_in_links", locals: { resource_name: resource_name } %>
|
||||
</div>
|
||||
<% if devise_mapping.omniauthable? && azure_ad_configured? %>
|
||||
<div class="azure-sign-in-actions">
|
||||
<%= render partial: "users/shared/azure_sign_in_links", locals: { resource_name: resource_name } %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,88 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Rails.application.configure do
|
||||
vars = ENV.select { |name, _| name =~ /^[[:alnum:]]*_AZURE_AD_APP_ID/ }
|
||||
config.x.azure_ad_apps = HashWithIndifferentAccess.new if vars.present?
|
||||
begin
|
||||
azure_app_ids = ENV.select { |name, _| name =~ /^[[:alnum:]]*_AZURE_AD_APP_ID/ }
|
||||
settings = ApplicationSettings.instance
|
||||
|
||||
vars.each do |name, value|
|
||||
azure_app_ids.each do |name, value|
|
||||
app_name = name.sub('_AZURE_AD_APP_ID', '')
|
||||
config.x.azure_ad_apps[value] = {}
|
||||
app_config = {}
|
||||
app_config['app_id'] = value
|
||||
|
||||
tenant_id = ENV["#{app_name}_AZURE_AD_TENANT_ID"]
|
||||
tenant_id = ENV.fetch("#{app_name}_AZURE_AD_TENANT_ID")
|
||||
raise StandardError, "No Tenant ID for #{app_name} Azure app" unless tenant_id
|
||||
|
||||
config.x.azure_ad_apps[value][:tenant_id] = tenant_id
|
||||
app_config['tenant_id'] = tenant_id
|
||||
|
||||
client_secret = ENV["#{app_name}_AZURE_AD_CLIENT_SECRET"]
|
||||
client_secret = ENV.fetch("#{app_name}_AZURE_AD_CLIENT_SECRET")
|
||||
raise StandardError, "No Client Secret for #{app_name} Azure app" unless client_secret
|
||||
|
||||
config.x.azure_ad_apps[value][:client_secret] = client_secret
|
||||
app_config['client_secret'] = client_secret
|
||||
|
||||
iss = ENV["#{app_name}_AZURE_AD_ISS"]
|
||||
iss = ENV.fetch("#{app_name}_AZURE_AD_ISS")
|
||||
raise StandardError, "No ISS for #{app_name} Azure app" unless iss
|
||||
|
||||
config.x.azure_ad_apps[value][:iss] = iss
|
||||
app_config['iss'] = iss
|
||||
|
||||
conf_url = ENV["#{app_name}_AZURE_AD_CONF_URL"]
|
||||
conf_url = ENV.fetch("#{app_name}_AZURE_AD_CONF_URL")
|
||||
raise StandardError, "No CONF_URL for #{app_name} Azure app" unless conf_url
|
||||
|
||||
config.x.azure_ad_apps[value][:conf_url] = conf_url
|
||||
app_config['conf_url'] = conf_url
|
||||
|
||||
provider = ENV["#{app_name}_AZURE_AD_PROVIDER_NAME"]
|
||||
provider = ENV.fetch("#{app_name}_AZURE_AD_PROVIDER_NAME")
|
||||
raise StandardError, "No PROVIDER_NAME for #{app_name} Azure app" unless provider
|
||||
|
||||
config.x.azure_ad_apps[value][:provider] = provider
|
||||
app_config['provider_name'] = provider
|
||||
|
||||
config.x.azure_ad_apps[value][:enable_sign_in] = ENV["#{app_name}_AZURE_AD_ENABLE_SIGN_IN"] == 'true'
|
||||
app_config['enable_sign_in'] = ENV["#{app_name}_AZURE_AD_ENABLE_SIGN_IN"] == 'true'
|
||||
|
||||
next unless config.x.azure_ad_apps[value][:enable_sign_in]
|
||||
next unless app_config['enable_sign_in']
|
||||
|
||||
config.x.azure_ad_apps[value][:sign_in_label] = ENV["#{app_name}_AZURE_AD_SIGN_IN_LABEL"] || 'Sign in with Azure AD'
|
||||
config.x.azure_ad_apps[value][:auto_link_on_sign_in] = ENV["#{app_name}_AZURE_AD_AUTO_LINK_ON_SIGN_IN"] == 'true'
|
||||
app_config['sign_in_label'] = ENV.fetch("#{app_name}_AZURE_AD_SIGN_IN_LABEL")
|
||||
app_config['auto_link_on_sign_in'] = ENV["#{app_name}_AZURE_AD_AUTO_LINK_ON_SIGN_IN"] == 'true'
|
||||
|
||||
if ENV["#{app_name}_AZURE_AD_SIGN_IN_POLICY"]
|
||||
config.x.azure_ad_apps[value][:sign_in_policy] = ENV["#{app_name}_AZURE_AD_SIGN_IN_POLICY"]
|
||||
app_config['sign_in_policy'] = ENV["#{app_name}_AZURE_AD_SIGN_IN_POLICY"]
|
||||
end
|
||||
|
||||
existing_index = settings.values['azure_ad_apps'].find_index { |v| v['app_id'] == value }
|
||||
if existing_index
|
||||
settings.values['azure_ad_apps'][existing_index] = app_config
|
||||
else
|
||||
settings.values['azure_ad_apps'] << app_config
|
||||
end
|
||||
end
|
||||
|
||||
# Checking additional configurations in ApplicationSettings JSON. Key and values should be strings there.
|
||||
begin
|
||||
if ApplicationSettings.instance.values['azure_ad_apps']&.is_a?(Array)
|
||||
config.x.azure_ad_apps ||= HashWithIndifferentAccess.new
|
||||
settings = ApplicationSettings.instance
|
||||
|
||||
settings.values['azure_ad_apps'].each do |azure_ad_app|
|
||||
app_config = {}
|
||||
app_id = azure_ad_app['app_id']
|
||||
Rails.logger.error('No app_id present for the entry in Azure app settings') && next unless app_id
|
||||
|
||||
app_config[:tenant_id] = azure_ad_app['tenant_id']
|
||||
Rails.logger.error("No tenant id for #{app_id} Azure app") && next unless app_config[:tenant_id]
|
||||
|
||||
app_config[:client_secret] = azure_ad_app['client_secret']
|
||||
Rails.logger.error("No client secret for #{app_id} Azure app") && next unless app_config[:client_secret]
|
||||
|
||||
app_config[:iss] = azure_ad_app['iss']
|
||||
Rails.logger.error("No iss for #{app_id} Azure app") && next unless app_config[:iss]
|
||||
|
||||
app_config[:conf_url] = azure_ad_app['conf_url']
|
||||
Rails.logger.error("No conf_url for #{app_id} Azure app") && next unless app_config[:conf_url]
|
||||
|
||||
app_config[:provider] = azure_ad_app['provider_name']
|
||||
Rails.logger.error("No provider_name for #{app_id} Azure app") && next unless app_config[:provider]
|
||||
|
||||
app_config[:enable_sign_in] = azure_ad_app['enable_sign_in'] == 'true'
|
||||
|
||||
if app_config[:enable_sign_in]
|
||||
app_config[:sign_in_label] = azure_ad_app['sign_in_label'] || 'Sign in with Azure AD'
|
||||
app_config[:auto_link_on_sign_in] = azure_ad_app['auto_link_on_sign_in'] == 'true'
|
||||
app_config[:sign_in_policy] = azure_ad_app['sign_in_policy'] if azure_ad_app['sign_in_policy']
|
||||
end
|
||||
|
||||
config.x.azure_ad_apps[app_id] = app_config
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::ActiveRecordError, PG::ConnectionBad
|
||||
Rails.logger.info('Not connected to database, skipping additional Azure AD configuration')
|
||||
end
|
||||
settings.save! if azure_app_ids.present?
|
||||
rescue ActiveRecord::ActiveRecordError, PG::ConnectionBad
|
||||
Rails.logger.info('Not connected to database, skipping additional Azure AD configuration')
|
||||
end
|
||||
|
|
|
@ -301,36 +301,6 @@ Devise.setup do |config|
|
|||
|
||||
Rails.application.config.x.disable_local_passwords = ENV['DISABLE_LOCAL_PASSWORDS'] == 'true'
|
||||
|
||||
if [ENV['OKTA_CLIENT_ID'], ENV['OKTA_CLIENT_SECRET'], ENV['OKTA_DOMAIN']].all?(&:present?)
|
||||
OKTA_OAUTH2_BASE_URL =
|
||||
if ENV['OKTA_AUTH_SERVER_ID'].blank?
|
||||
"https://#{ENV['OKTA_DOMAIN']}/oauth2"
|
||||
else
|
||||
"https://#{ENV['OKTA_DOMAIN']}/oauth2/#{ENV['OKTA_AUTH_SERVER_ID']}"
|
||||
end
|
||||
client_options = {
|
||||
site: "https://#{ENV['OKTA_DOMAIN']}",
|
||||
authorize_url: "#{OKTA_OAUTH2_BASE_URL}/v1/authorize",
|
||||
token_url: "#{OKTA_OAUTH2_BASE_URL}/v1/token",
|
||||
user_info_url: "#{OKTA_OAUTH2_BASE_URL}/v1/userinfo"
|
||||
}
|
||||
client_options[:audience] = ENV['OKTA_CLIENT_ID'] if ENV['OKTA_AUDIENCE'].present?
|
||||
if ENV['OKTA_AUTH_SERVER_ID'].present?
|
||||
client_options[:authorization_server] = ENV['OKTA_AUTH_SERVER_ID']
|
||||
else
|
||||
client_options[:use_org_auth_server] = true
|
||||
end
|
||||
config.omniauth(
|
||||
:okta,
|
||||
ENV['OKTA_CLIENT_ID'],
|
||||
ENV['OKTA_CLIENT_SECRET'],
|
||||
scope: 'openid profile email',
|
||||
fields: %w(profile email),
|
||||
client_options: client_options,
|
||||
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.
|
||||
|
|
18
config/initializers/okta.rb
Normal file
18
config/initializers/okta.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
begin
|
||||
settings = ApplicationSettings.instance
|
||||
provider_conf = settings.values['okta']
|
||||
if provider_conf.blank? && %w(OKTA_CLIENT_ID OKTA_CLIENT_SECRET OKTA_DOMAIN).all? { |v| ENV.fetch(v, nil).present? }
|
||||
provider_conf = {}
|
||||
provider_conf['client_id'] = ENV.fetch('OKTA_CLIENT_ID')
|
||||
provider_conf['client_secret'] = ENV.fetch('OKTA_CLIENT_SECRET')
|
||||
provider_conf['domain'] = ENV.fetch('OKTA_DOMAIN')
|
||||
provider_conf['auth_server_id'] = ENV['OKTA_AUTH_SERVER_ID'] if ENV['OKTA_AUTH_SERVER_ID'].present?
|
||||
provider_conf['audience'] = ENV['OKTA_AUDIENCE'] if ENV['OKTA_AUDIENCE'].present?
|
||||
settings.values['okta'] = provider_conf
|
||||
settings.save!
|
||||
end
|
||||
rescue ActiveRecord::ActiveRecordError, PG::ConnectionBad
|
||||
Rails.logger.info('Not connected to database, skipping additional Okta configuration')
|
||||
end
|
|
@ -3,7 +3,8 @@
|
|||
require 'omniauth/strategies/custom_azure_active_directory'
|
||||
|
||||
AZURE_SETUP_PROC = lambda do |env|
|
||||
providers = Rails.configuration.x.azure_ad_apps.select { |_, v| v[:enable_sign_in] == true }
|
||||
settings = ApplicationSettings.instance
|
||||
providers = settings.values['azure_ad_apps'].select { |v| v['enable_sign_in'] }
|
||||
raise StandardError, 'No Azure AD config available for sign in' if providers.blank?
|
||||
|
||||
req = Rack::Request.new(env)
|
||||
|
@ -11,28 +12,60 @@ AZURE_SETUP_PROC = lambda do |env|
|
|||
if providers.size > 1
|
||||
if req.params['id_token'].present? # Callback phase
|
||||
unverified_jwt_payload, = JWT.decode(req.params['id_token'], nil, false)
|
||||
raise StandardError, 'No Azure AD config available for sign in' if providers[unverified_jwt_payload['aud']].blank?
|
||||
|
||||
provider_id = unverified_jwt_payload['aud']
|
||||
provider_conf = providers.select { |v| v['app_id'] == unverified_jwt_payload['aud'] }
|
||||
else # Authorization phase
|
||||
raise ActionController::ParameterMissing, 'Provider name is missing' if req.params['provider'].blank?
|
||||
|
||||
provider_id = providers.select { |_, v| v[:provider] == req.params['provider'] }.keys.first
|
||||
raise StandardError, 'No Azure AD config available for sign in' if provider_id.blank?
|
||||
provider_conf = providers.find { |v| v['provider_name'] == req.params['provider'] }
|
||||
end
|
||||
raise StandardError, 'No Azure AD config available for sign in' if provider_conf.blank?
|
||||
end
|
||||
|
||||
provider_id ||= providers.keys.first
|
||||
provider_conf = providers[provider_id]
|
||||
env['omniauth.strategy'].options[:client_id] = provider_id.to_s
|
||||
env['omniauth.strategy'].options[:client_secret] = provider_conf[:client_secret]
|
||||
env['omniauth.strategy'].options[:tenant_id] = provider_conf[:tenant_id]
|
||||
env['omniauth.strategy'].options[:sign_in_policy] = provider_conf[:sign_in_policy]
|
||||
provider_conf ||= providers.first
|
||||
env['omniauth.strategy'].options[:client_id] = provider_conf['app_id']
|
||||
env['omniauth.strategy'].options[:client_secret] = provider_conf['client_secret']
|
||||
env['omniauth.strategy'].options[:tenant_id] = provider_conf['tenant_id']
|
||||
env['omniauth.strategy'].options[:sign_in_policy] = provider_conf['sign_in_policy']
|
||||
env['omniauth.strategy'].options[:name] = 'customazureactivedirectory'
|
||||
end
|
||||
|
||||
OKTA_SETUP_PROC = lambda do |env|
|
||||
settings = ApplicationSettings.instance
|
||||
provider_conf = settings.values['okta']
|
||||
raise StandardError, 'No Okta config available for sign in' if provider_conf.blank?
|
||||
|
||||
oauth2_base_url =
|
||||
if provider_conf['auth_server_id'].blank?
|
||||
"https://#{provider_conf['domain']}/oauth2"
|
||||
else
|
||||
"https://#{provider_conf['domain']}/oauth2/#{provider_conf['auth_server_id']}"
|
||||
end
|
||||
|
||||
client_options = {
|
||||
site: "https://#{provider_conf['domain']}",
|
||||
authorize_url: "#{oauth2_base_url}/v1/authorize",
|
||||
token_url: "#{oauth2_base_url}/v1/token",
|
||||
user_info_url: "#{oauth2_base_url}/v1/userinfo"
|
||||
}
|
||||
client_options[:audience] = provider_conf['audience'] if provider_conf['audience'].present?
|
||||
if provider_conf['auth_server_id'].present?
|
||||
client_options[:authorization_server] = provider_conf['auth_server_id']
|
||||
client_options[:use_org_auth_server] = false
|
||||
else
|
||||
client_options[:use_org_auth_server] = true
|
||||
end
|
||||
|
||||
env['omniauth.strategy'].options[:client_id] = provider_conf['client_id']
|
||||
env['omniauth.strategy'].options[:client_secret] = provider_conf['client_secret']
|
||||
env['omniauth.strategy'].options[:client_options] = client_options
|
||||
end
|
||||
|
||||
Rails.application.config.middleware.use OmniAuth::Builder do
|
||||
provider OmniAuth::Strategies::CustomAzureActiveDirectory, setup: AZURE_SETUP_PROC
|
||||
end
|
||||
|
||||
Rails.application.config.middleware.use OmniAuth::Builder do
|
||||
provider OmniAuth::Strategies::Okta, setup: OKTA_SETUP_PROC
|
||||
end
|
||||
|
||||
OmniAuth.config.logger = Rails.logger
|
||||
|
|
|
@ -33,6 +33,7 @@ en:
|
|||
password_placeholder: "Enter password"
|
||||
remember_me: "Remember me"
|
||||
submit: "Log in"
|
||||
azure_ad_submit: "Sign in with Azure AD"
|
||||
2fa:
|
||||
title: "Two-factor authentication"
|
||||
description: "Enter the one-time code found in your authenticator app to log in to SciNote."
|
||||
|
|
Loading…
Reference in a new issue