Merge branch '15529-federated-user-accounts' refs #15529
[arvados.git] / services / api / app / controllers / user_sessions_controller.rb
index 1889d74eaa891dc980889cfd00491f54935ee08f..49af414310782ba25b55679840329c9fcfe18ead 100644 (file)
@@ -3,17 +3,21 @@
 # SPDX-License-Identifier: AGPL-3.0
 
 class UserSessionsController < ApplicationController
-  before_filter :require_auth_scope, :only => [ :destroy ]
+  before_action :require_auth_scope, :only => [ :destroy ]
 
-  skip_before_filter :set_cors_headers
-  skip_before_filter :find_object_by_uuid
-  skip_before_filter :render_404_if_no_object
+  skip_before_action :set_cors_headers
+  skip_before_action :find_object_by_uuid
+  skip_before_action :render_404_if_no_object
 
   respond_to :html
 
   # omniauth callback method
   def create
-    omniauth = env['omniauth.auth']
+    if !Rails.configuration.Login.LoginCluster.empty? and Rails.configuration.Login.LoginCluster != Rails.configuration.ClusterID
+      raise "Local login disabled when LoginCluster is set"
+    end
+
+    omniauth = request.env['omniauth.auth']
 
     identity_url_ok = (omniauth['info']['identity_url'].length > 0) rescue false
     unless identity_url_ok
@@ -52,7 +56,7 @@ class UserSessionsController < ApplicationController
                       :first_name => omniauth['info']['first_name'],
                       :last_name => omniauth['info']['last_name'],
                       :identity_url => omniauth['info']['identity_url'],
-                      :is_active => Rails.configuration.new_users_are_active,
+                      :is_active => Rails.configuration.Users.NewUsersAreActive,
                       :owner_uuid => system_user_uuid)
       if omniauth['info']['username']
         user.set_initial_username(requested: omniauth['info']['username'])
@@ -80,6 +84,16 @@ class UserSessionsController < ApplicationController
     # For the benefit of functional and integration tests:
     @user = user
 
+    if user.uuid[0..4] != Rails.configuration.ClusterID
+      # Actually a remote user
+      # Send them to their home cluster's login
+      rh = Rails.configuration.RemoteClusters[user.uuid[0..4]]
+      remote, return_to_url = params[:return_to].split(',', 2)
+      @remotehomeurl = "#{rh.Scheme || "https"}://#{rh.Host}/login?remote=#{Rails.configuration.ClusterID}&return_to=#{return_to_url}"
+      render
+      return
+    end
+
     # prevent ArvadosModel#before_create and _update from throwing
     # "unauthorized":
     Thread.current[:user] = user
@@ -120,7 +134,7 @@ class UserSessionsController < ApplicationController
 
     flash[:notice] = 'You have logged off'
     return_to = params[:return_to] || root_url
-    redirect_to "#{Rails.configuration.sso_provider_url}/users/sign_out?redirect_uri=#{CGI.escape return_to}"
+    redirect_to "#{Rails.configuration.Services.SSO.ExternalURL}/users/sign_out?redirect_uri=#{CGI.escape return_to}"
   end
 
   # login - Just bounce to /auth/joshid. The only purpose of this function is
@@ -141,13 +155,30 @@ class UserSessionsController < ApplicationController
     end
     p = []
     p << "auth_provider=#{CGI.escape(params[:auth_provider])}" if params[:auth_provider]
-    if params[:return_to]
-      # Encode remote param inside callback's return_to, so that we'll get it on
-      # create() after login.
-      remote_param = params[:remote].nil? ? '' : params[:remote]
-      p << "return_to=#{CGI.escape(remote_param + ',' + params[:return_to])}"
+
+    if !Rails.configuration.Login.LoginCluster.empty? and Rails.configuration.Login.LoginCluster != Rails.configuration.ClusterID
+      host = ApiClientAuthorization.remote_host(uuid_prefix: Rails.configuration.Login.LoginCluster)
+      if not host
+        raise "LoginCluster #{Rails.configuration.Login.LoginCluster} missing from RemoteClusters"
+      end
+      scheme = "https"
+      cluster = Rails.configuration.RemoteClusters[Rails.configuration.Login.LoginCluster]
+      if cluster and cluster['Scheme'] and !cluster['Scheme'].empty?
+        scheme = cluster['Scheme']
+      end
+      login_cluster = "#{scheme}://#{host}"
+      p << "remote=#{CGI.escape(params[:remote])}" if params[:remote]
+      p << "return_to=#{CGI.escape(params[:return_to])}" if params[:return_to]
+      redirect_to "#{login_cluster}/login?#{p.join('&')}"
+    else
+      if params[:return_to]
+        # Encode remote param inside callback's return_to, so that we'll get it on
+        # create() after login.
+        remote_param = params[:remote].nil? ? '' : params[:remote]
+        p << "return_to=#{CGI.escape(remote_param + ',' + params[:return_to])}"
+      end
+      redirect_to "/auth/joshid?#{p.join('&')}"
     end
-    redirect_to "/auth/joshid?#{p.join('&')}"
   end
 
   def send_api_token_to(callback_url, user, remote=nil)