diff --git a/Gemfile b/Gemfile index f863065a11..49da6cd18c 100644 --- a/Gemfile +++ b/Gemfile @@ -95,9 +95,9 @@ gem 'string-similarity' gem 'inline_svg' # ISO language codes and flags +gem 'countries', '~> 5.7' gem 'flag-icons-rails', '~> 3.4' gem 'iso-639', '~> 0.3.6' -gem 'countries', '~> 5.7' # Custom API client gem 'ontologies_api_client', git: 'https://github.com/lifewatch-eric/ontologies_api_ruby_client.git', branch: 'master' @@ -108,14 +108,14 @@ gem 'net-http', '~> 0.3.2' # Multi-Provider Authentication gem 'omniauth' -gem 'omniauth-rails_csrf_protection' gem 'omniauth-github' gem 'omniauth-google-oauth2' -gem 'omniauth-keycloak' +gem 'omniauth-keycloak', '~> 1.4' gem 'omniauth-orcid' +gem 'omniauth-rails_csrf_protection', '~> 1.0', '>= 1.0.1' # Used to generate colors randomly -gem "color", "~> 1.8" +gem 'color', '~> 1.8' group :staging, :production, :appliance do # Application performance monitoring @@ -157,9 +157,9 @@ group :development do # Internationalization tasks # gem 'i18n-debug' + gem 'deepl-rb' gem 'i18n-tasks' gem 'i18n-tasks-csv', '~> 1.1' - gem 'deepl-rb' # Email preview in the browser gem 'letter_opener_web', '~> 2.0' @@ -184,4 +184,4 @@ group :test do gem 'rspec-rails' end -gem 'openid_connect', '~> 2.2.0' \ No newline at end of file +gem 'openid_connect', '~> 2.2.0' diff --git a/Gemfile.lock b/Gemfile.lock index df7aeae651..3e0bd34d3d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM bugsnag (6.27.1) concurrent-ruby (~> 1.0) builder (3.3.0) - capistrano (3.19.1) + capistrano (3.19.2) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) @@ -151,7 +151,7 @@ GEM addressable csv (3.3.0) dalli (3.2.8) - date (3.3.4) + date (3.4.0) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) @@ -162,7 +162,7 @@ GEM ed25519 (1.3.0) erubi (1.13.0) erubis (2.7.0) - excon (0.112.0) + excon (1.2.0) execjs (2.10.0) faraday (2.0.1) faraday-net_http (~> 2.0) @@ -181,7 +181,7 @@ GEM sass-rails globalid (1.2.1) activesupport (>= 6.1) - graphql (2.3.19) + graphql (2.4.2) base64 fiber-storage graphql-client (0.23.0) @@ -243,7 +243,7 @@ GEM railties (>= 3.2.16) jsbundling-rails (1.3.1) railties (>= 6.0.0) - json (2.7.4) + json (2.8.1) json-jwt (1.16.7) activesupport (>= 4.2) aes_key_wrap @@ -296,7 +296,7 @@ GEM mime-types (3.6.0) logger mime-types-data (~> 3.2015) - mime-types-data (3.2024.1001) + mime-types-data (3.2024.1105) mini_mime (1.1.5) minitest (5.25.1) msgpack (1.7.3) @@ -309,7 +309,7 @@ GEM time net-http (0.3.2) uri - net-imap (0.4.17) + net-imap (0.4.18) date net-protocol net-pop (0.1.2) @@ -324,7 +324,7 @@ GEM net-protocol net-ssh (7.3.0) netrc (0.11.0) - newrelic_rpm (9.14.0) + newrelic_rpm (9.15.0) nio4r (2.7.4) nokogiri (1.15.6-x86_64-darwin) racc (~> 1.4) @@ -337,7 +337,7 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) - oj (3.16.6) + oj (3.16.7) bigdecimal (>= 3.0) ostruct (>= 0.2) omniauth (2.1.2) @@ -378,16 +378,16 @@ GEM validate_email validate_url webfinger (~> 2.0) - ostruct (0.6.0) + ostruct (0.6.1) parallel (1.26.3) - parser (3.3.5.0) + parser (3.3.6.0) ast (~> 2.4.1) racc popper_js (1.16.1) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - psych (5.1.2) + psych (5.2.0) stringio public_suffix (5.1.1) puma (5.6.9) @@ -448,7 +448,7 @@ GEM json redcarpet (3.6.0) regexp_parser (2.9.2) - reline (0.5.10) + reline (0.5.11) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) @@ -467,7 +467,7 @@ GEM rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (7.0.1) + rspec-rails (7.1.0) actionpack (>= 7.0) activesupport (>= 7.0) railties (>= 7.0) @@ -476,7 +476,7 @@ GEM rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-support (3.13.1) - rubocop (1.67.0) + rubocop (1.68.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -486,7 +486,7 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) + rubocop-ast (1.34.1) parser (>= 3.3.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) @@ -539,7 +539,7 @@ GEM stimulus-rails (1.3.4) railties (>= 6.0.0) string-similarity (2.1.0) - stringio (3.1.1) + stringio (3.1.2) swd (2.0.3) activesupport (>= 3) attr_required (>= 0.0.5) @@ -552,9 +552,9 @@ GEM execjs (>= 0.3.0, < 3) thor (1.3.2) tilt (2.4.0) - time (0.4.0) + time (0.4.1) date - timeout (0.4.1) + timeout (0.4.2) turbo-rails (2.0.11) actionpack (>= 6.0.0) railties (>= 6.0.0) @@ -562,7 +562,7 @@ GEM concurrent-ruby (~> 1.0) unaccent (0.4.0) unicode-display_width (2.6.0) - uri (0.13.1) + uri (1.0.1) validate_email (0.1.6) activemodel (>= 3.0) mail (>= 2.2.5) @@ -648,9 +648,9 @@ DEPENDENCIES omniauth omniauth-github omniauth-google-oauth2 - omniauth-keycloak + omniauth-keycloak (~> 1.4) omniauth-orcid - omniauth-rails_csrf_protection + omniauth-rails_csrf_protection (~> 1.0, >= 1.0.1) ontologies_api_client! openid_connect (~> 2.2.0) pry diff --git a/app/assets/stylesheets/login.scss b/app/assets/stylesheets/login.scss index f77d8a6b71..0577319d0d 100644 --- a/app/assets/stylesheets/login.scss +++ b/app/assets/stylesheets/login.scss @@ -1,5 +1,6 @@ .login-form{ margin-top: 10px; + margin-bottom: 40px; padding: 37px 41px; box-shadow: rgba(0, 0, 0, 0.08) 0px 20px 50px; border-radius: 14px; @@ -60,4 +61,4 @@ } .login-active-sso path{ fill: var(--primary-color) -} \ No newline at end of file +} diff --git a/app/controllers/oauth2_controller.rb b/app/controllers/oauth2_controller.rb deleted file mode 100644 index 33a89ae7fb..0000000000 --- a/app/controllers/oauth2_controller.rb +++ /dev/null @@ -1,156 +0,0 @@ -class Oauth2Controller < ApplicationController - - skip_before_action :verify_authenticity_token - - def index - # Sets the redirect properties - if params[:redirect] - # Get the original, encoded redirect - uri = URI.parse(request.url) - orig_params = Hash[uri.query.split("&").map {|e| e.split("=",2)}].symbolize_keys - session[:redirect] = orig_params[:redirect] - else - session[:redirect] = request.referer - end - - redirect_to login_index_path - end - - def login - - client = build_oauth2_client - - session[:state] = SecureRandom.hex(16) - session[:nonce] = SecureRandom.hex(16) - - # Authorization Request - authorization_uri = client.authorization_uri( - scope: [], - state: session[:state], - nonce: session[:nonce] - ) - redirect_to authorization_uri, allow_other_host: true - end - - def authorize_callback - # Parameter checking - code = params[:code] - state = params[:state] - - @errors = [] - - if code.nil? - @errors.append("Missing code argument in the callback from the Identity Provider") - end - - if state.nil? - @errors.append("Missing state argument in the callback from the Identity Provider") - end - - if state != session[:state] - @errors.append("The state argument in the callback from the Identity Provider does not match the expected value") - end - - unless @errors.empty? - flash[:notice] = @errors.join("
").html_safe - redirect_to_home - end - - # Request tokens - client = build_oauth2_client - client.authorization_code = code - - access_token = client.access_token! - - # Authenticate the user with the access token to obtain the apikey - # - logged_in_user = LinkedData::Client::HTTP.post("#{LinkedData::Client.settings.rest_url}/users/authenticate", { token: access_token.access_token }) - logged_in_user.id_token = access_token.id_token - - if logged_in_user && !logged_in_user.errors - loginInternal(logged_in_user) - redirect = "/" - - if session[:redirect] - redirect = CGI.unescape(session[:redirect]) - end - - redirect_to redirect - else - errorMsg = "Login Failed" - if logged_in_user&.errors - errorMsg += "
" - errorMsg += logged_in_user.errors.join("
") - end - flash[:error] = errorMsg.html_safe - redirect_to_home - end - end - - def loginInternal(user) - return unless user - session[:user] = user - custom_ontologies_text = session[:user].customOntology && !session[:user].customOntology.empty? ? "The display is now based on your Custom Ontology Set." : "" - notice = "Welcome " + user.username.to_s + "! " + custom_ontologies_text - flash[:success] = notice.html_safe - end - - def logout - - redirect = request.referer || "/" - external_redirect_allowed = false - - # Delete internal security context - - if session[:admin_user] - old_user = session[:user] - session[:user] = session[:admin_user] - session.delete(:admin_user) - flash[:success] = "Logged out #{old_user.username}, returned to #{session[:user].username}".html_safe - else - idt = session[:user]&.id_token - - session[:user] = nil - flash[:success] = "You have successfully logged out" - - if redirect == "/" - redirect = request.protocol + request.host_with_port + "/" - end - redirect = build_url_with_params(@@configStruct.end_session_endpoint, {client_id: @@configStruct.client_id, id_token_hint: idt, post_logout_redirect_uri: redirect}) - end - - # Start an RP-initiated logout process - redirect_to redirect, allow_other_host: true - end - - def self.config(&block) - raise "missing code block" unless block_given? - @@configStruct = OpenStruct.new - - yield @@configStruct - end - - private - - def build_oauth2_client - raise 'OAUTH2 has not been configured' unless @@configStruct - OpenIDConnect::Client.new( - identifier: @@configStruct.client_id, - secret: @@configStruct.client_secret, - redirect_uri: request.protocol + request.host_with_port + "/oauth2/authorize_callback", - host: @@configStruct.host, - authorization_endpoint: @@configStruct.authorization_endpoint, - token_endpoint: @@configStruct.token_endpoint, - userinfo_endpoint: @@configStruct.userinfo_endpoint - ) - end - - def build_url_with_params(url, params) - # See https://stackoverflow.com/a/26867426 - uri = URI.parse(url) - new_query_ar = URI.decode_www_form(uri.query || '') - params.each_key { |k| new_query_ar << [k, params[k]] } - uri.query = URI.encode_www_form(new_query_ar) - uri.to_s - end -end \ No newline at end of file diff --git a/app/views/login/index.html.haml b/app/views/login/index.html.haml index 0d39f910b2..c05ce8ba4e 100644 --- a/app/views/login/index.html.haml +++ b/app/views/login/index.html.haml @@ -19,16 +19,18 @@ = t('login.no_account') %a.text-decoration-none{:href => new_user_path}= t('login.register') %hr.divider.w-100.mb-4.mt-4 - %div.d-flex.justify-content-around.flew-wrap + %p.dont-have-account + Or connect using + %div.d-flex.justify-content-center.flew-wrap - omniauth_providers_info.each do |provider, config| - if config[:enable] = button_to "/auth/#{config[:name] || config[:strategy] || provider}", - class: 'btn btn-lg',disabled: !config[:enable] ,style:'width: 70px', title: t('login.login_with_provider', provider: provider.to_s.humanize), 'data-turbo': false do; + class: 'btn btn-lg', disabled: !config[:enable] , title: t('login.login_with_provider', provider: provider.to_s.humanize), 'data-turbo': false do; - if config[:icon] - = inline_svg "icons/#{config[:icon]}", class: 'login-active-sso' + = inline_svg "#{config[:icon]}", class: 'login-active-sso' - else = provider.to_s.humanize - else .disabled-login-sso = render Display::InfoTooltipComponent.new(text: "#{provider.to_s.humanize} is disabled") do - = inline_svg "icons/#{config[:icon]}", width: "40", height: "40" \ No newline at end of file + = inline_svg "icons/#{config[:icon]}", width: "40", height: "40" diff --git a/config/initializers/oauth2.rb b/config/initializers/oauth2.rb deleted file mode 100644 index ab92ae7620..0000000000 --- a/config/initializers/oauth2.rb +++ /dev/null @@ -1,12 +0,0 @@ -if $SSO_ENABLED - # Oauth2Controller.config do |config| - # idpMetadataJSON = JSON.parse(IO.read(Rails.root.join("config/oauth2/idp-configuration.json")), {symbolize_names: true}) - # - # config.client_id = Rails.application.credentials.oauth2[:client_id] - # config.client_secret = Rails.application.credentials.oauth2[:client_secret] - # config.authorization_endpoint = idpMetadataJSON[:authorization_endpoint] - # config.token_endpoint = idpMetadataJSON[:token_endpoint] - # config.userinfo_endpoint = idpMetadataJSON[:userinfo_endpoint] - # config.end_session_endpoint = idpMetadataJSON[:end_session_endpoint] - # end -end diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index c7c4027c3e..3ca7354cc6 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,5 +1,8 @@ Rails.application.config.middleware.use OmniAuth::Builder do Array($OMNIAUTH_PROVIDERS).each do |provider, config| - provider config[:strategy] || provider, config[:client_id], config[:client_secret], client_options: {}.merge(config[:client_options].to_h) + provider config[:strategy] || provider, config[:client_id], + config[:client_secret], + client_options: {}.merge(config[:client_options].to_h), + name: config[:name] end -end \ No newline at end of file +end