21700: Install Bundler system-wide in Rails postinst
[arvados.git] / services / api / app / controllers / user_sessions_controller.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class UserSessionsController < ApplicationController
6   before_action :require_auth_scope, :only => [ :destroy ]
7
8   skip_before_action :set_cors_headers
9   skip_before_action :find_object_by_uuid
10   skip_before_action :render_404_if_no_object
11
12   respond_to :html
13
14   def login
15     return send_error "Legacy code path no longer supported", status: 404
16   end
17
18   def logout
19     return send_error "Legacy code path no longer supported", status: 404
20   end
21
22   # create a new session
23   def create
24     remote, return_to_url = params[:return_to].split(',', 2)
25     if params[:provider] != 'controller' ||
26        return_to_url != 'https://controller.api.client.invalid'
27       return send_error "Legacy code path no longer supported", status: 404
28     end
29     if request.headers['Authorization'] != 'Bearer ' + Rails.configuration.SystemRootToken
30       return send_error('Invalid authorization header', status: 401)
31     end
32     if remote == ''
33       remote = nil
34     elsif remote !~ /^[0-9a-z]{5}$/
35       return send_error 'Invalid remote cluster id', status: 400
36     end
37     # arvados-controller verified the user and is passing auth_info
38     # in request params.
39     authinfo = SafeJSON.load(params[:auth_info])
40     max_expires_at = authinfo["expires_at"]
41
42     if !authinfo['user_uuid'].blank?
43       user = User.find_by_uuid(authinfo['user_uuid'])
44       if !user
45         Rails.logger.warn "Nonexistent user_uuid in authinfo #{authinfo.inspect}"
46         return redirect_to login_failure_url
47       end
48     else
49       begin
50         user = User.register(authinfo)
51       rescue => e
52         Rails.logger.warn "User.register error #{e}"
53         Rails.logger.warn "authinfo was #{authinfo.inspect}"
54         return redirect_to login_failure_url
55       end
56     end
57
58     # For the benefit of functional and integration tests:
59     @user = user
60
61     # prevent ArvadosModel#before_create and _update from throwing
62     # "unauthorized":
63     Thread.current[:user] = user
64
65     user.save or raise Exception.new(user.errors.messages)
66
67     return send_api_token_to(return_to_url, user, remote, max_expires_at)
68   end
69
70   # Omniauth failure callback
71   def failure
72     flash[:notice] = params[:message]
73   end
74
75   def send_api_token_to(callback_url, user, remote=nil, token_expiration=nil)
76     # Give the API client a token for making API calls on behalf of
77     # the authenticated user
78
79     # Stub: automatically register all new API clients
80     api_client_url_prefix = callback_url.match(%r{^.*?://[^/]+})[0] + '/'
81     act_as_system_user do
82       @api_client = ApiClient.
83         find_or_create_by(url_prefix: api_client_url_prefix)
84     end
85     if Rails.configuration.Login.TokenLifetime > 0
86       if token_expiration == nil
87         token_expiration = db_current_time + Rails.configuration.Login.TokenLifetime
88       else
89         token_expiration = [token_expiration, db_current_time + Rails.configuration.Login.TokenLifetime].min
90       end
91     end
92
93     @api_client_auth = ApiClientAuthorization.
94       new(user: user,
95           api_client: @api_client,
96           created_by_ip_address: remote_ip,
97           expires_at: token_expiration,
98           scopes: ["all"])
99     @api_client_auth.save!
100
101     if callback_url.index('?')
102       callback_url += '&'
103     else
104       callback_url += '?'
105     end
106     if remote.nil?
107       token = @api_client_auth.token
108     else
109       token = @api_client_auth.salted_token(remote: remote)
110     end
111     callback_url += 'api_token=' + token
112     redirect_to callback_url, allow_other_host: true
113   end
114
115   def cross_origin_forbidden
116     send_error 'Forbidden', status: 403
117   end
118 end