zuora_connect 2.0.5zj → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/zuora_connect/static_controller.rb +17 -4
- data/app/helpers/zuora_connect/application_helper.rb +0 -10
- data/app/models/zuora_connect/app_instance_base.rb +66 -109
- data/app/models/zuora_connect/telegraf.rb +2 -2
- data/app/models/zuora_connect/zuora_user.rb +0 -1
- data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +65 -0
- data/app/views/zuora_connect/static/invalid_launch_request.html.erb +81 -0
- data/app/views/zuora_connect/static/launch.html.erb +75 -74
- data/app/views/zuora_connect/static/permission_error.html.erb +80 -0
- data/app/views/zuora_connect/static/session_error.html.erb +63 -0
- data/config/routes.rb +2 -0
- data/lib/middleware/request_id_middleware.rb +1 -1
- data/lib/resque/plugins/custom_logger.rb +1 -1
- data/lib/zuora_connect.rb +42 -59
- data/lib/zuora_connect/configuration.rb +3 -3
- data/lib/zuora_connect/controllers/helpers.rb +183 -253
- data/lib/zuora_connect/engine.rb +1 -2
- data/lib/zuora_connect/railtie.rb +6 -10
- data/lib/zuora_connect/version.rb +1 -1
- data/lib/zuora_connect/views/helpers.rb +9 -0
- metadata +54 -54
- data/app/views/zuora_connect/static/error_handled.html.erb +0 -77
- data/app/views/zuora_connect/static/error_unhandled.erb +0 -82
- data/config/initializers/patches.rb +0 -9
- data/db/migrate/20190520232222_add_unique_index.rb +0 -6
- data/lib/middleware/json_parse_errors.rb +0 -22
data/config/routes.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
ZuoraConnect::Engine.routes.draw do
|
2
2
|
get '/health' => 'static#health'
|
3
3
|
get '/internal/data' => 'static#metrics'
|
4
|
+
get '/invalid_session' => 'static#session_error', :as => :invalid_session
|
5
|
+
get '/invalid_instance' => "static#invalid_app_instance_error", :as => :invalid_instance
|
4
6
|
post '/initialize_app' => 'static#initialize_app'
|
5
7
|
|
6
8
|
namespace :api do
|
@@ -7,7 +7,7 @@ module Resque
|
|
7
7
|
module Plugins
|
8
8
|
module CustomLogger
|
9
9
|
def before_perform(*args)
|
10
|
-
Rails.logger.with_fields = { trace_id: SecureRandom.uuid, name: "RailsWorker"} if Rails.logger.class.to_s == 'Ougai::Logger'
|
10
|
+
Rails.logger.with_fields = { trace_id: SecureRandom.uuid, name: "RailsWorker"} if Rails.logger.class.to_s == 'Ougai::Logger'
|
11
11
|
case args.class.to_s
|
12
12
|
when "Array"
|
13
13
|
if args.first.class == Hash
|
data/lib/zuora_connect.rb
CHANGED
@@ -2,6 +2,7 @@ require 'zuora_connect/configuration'
|
|
2
2
|
require "zuora_connect/engine"
|
3
3
|
require 'zuora_connect/exceptions'
|
4
4
|
require 'zuora_connect/controllers/helpers'
|
5
|
+
require 'zuora_connect/views/helpers'
|
5
6
|
require 'zuora_connect/railtie'
|
6
7
|
require 'resque/additions'
|
7
8
|
require 'resque/dynamic_queues'
|
@@ -24,49 +25,30 @@ module ZuoraConnect
|
|
24
25
|
else
|
25
26
|
@logger ||= custom_logger(name: "Connect", level: Rails.logger.level)
|
26
27
|
end
|
27
|
-
end
|
28
|
+
end
|
28
29
|
|
29
30
|
def custom_logger(name: "", level: Rails.logger.present? ? Rails.logger.level : MonoLogger::INFO, type: :ougai)
|
30
31
|
#puts name + ' - ' + {Logger::WARN => 'Logger::WARN', Logger::ERROR => 'Logger::ERROR', Logger::DEBUG => 'Logger::DEBUG', Logger::INFO => 'Logger::INFO' }[level] + ' - '
|
31
32
|
if type == :ougai
|
32
33
|
require 'ougai'
|
33
|
-
require "ougai/formatters/customizable"
|
34
34
|
#logger = Ougai::Logger.new(MonoLogger.new(STDOUT))
|
35
|
-
logger = Ougai::Logger.new(STDOUT)
|
35
|
+
logger = Ougai::Logger.new(STDOUT)
|
36
|
+
logger.formatter = Ougai::Formatters::ConnectFormatter.new(name)
|
36
37
|
logger.level = level
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
if logitems.present?
|
48
|
-
data[:tenant_ids] = logitems[:tenant_ids] if logitems[:tenant_ids].present?
|
49
|
-
data[:organization] = logitems[:organization] if logitems[:organization].present?
|
50
|
-
end
|
38
|
+
logger.before_log = lambda do |data|
|
39
|
+
data[:trace_id] = ZuoraConnect::RequestIdMiddleware.request_id if ZuoraConnect::RequestIdMiddleware.request_id.present?
|
40
|
+
data[:zuora_trace_id] = ZuoraConnect::RequestIdMiddleware.zuora_request_id if ZuoraConnect::RequestIdMiddleware.zuora_request_id.present?
|
41
|
+
#data[:traces] = {amazon_id: data[:trace_id], zuora_id: data[:zuora_trace_id]}
|
42
|
+
if !['ElasticAPM', 'ResqueScheduler', 'ResquePool', 'Resque', 'Makara'].include?(name)
|
43
|
+
if Thread.current[:appinstance].present?
|
44
|
+
data[:app_instance_id] = Thread.current[:appinstance].id
|
45
|
+
logitems = Thread.current[:appinstance].logitems
|
46
|
+
if logitems.present? && logitems.class == Hash
|
47
|
+
data[:tenant_ids] = logitems[:tenant_ids] if logitems[:tenant_ids].present?
|
48
|
+
data[:organization] = logitems[:organization] if logitems[:organization].present?
|
51
49
|
end
|
52
50
|
end
|
53
51
|
end
|
54
|
-
else
|
55
|
-
logger.formatter = Ougai::Formatters::Customizable.new(
|
56
|
-
format_err: proc do |data|
|
57
|
-
next nil unless data.key?(:err)
|
58
|
-
err = data.delete(:err)
|
59
|
-
" #{err[:name]} (#{err[:message]})\n #{err[:stack]}"
|
60
|
-
end,
|
61
|
-
format_data: proc do |data|
|
62
|
-
format('%s %s: %s', 'DATA'.ljust(6), Time.now.strftime('%FT%T.%6NZ'), "#{data.to_json}") if data.present?
|
63
|
-
end,
|
64
|
-
format_msg: proc do |severity, datetime, _progname, data|
|
65
|
-
msg = data.delete(:msg)
|
66
|
-
format('%s %s: %s', severity.ljust(6), datetime, msg)
|
67
|
-
end
|
68
|
-
)
|
69
|
-
logger.formatter.datetime_format = '%FT%T.%6NZ'
|
70
52
|
end
|
71
53
|
else
|
72
54
|
logger = MonoLogger.new(STDOUT)
|
@@ -76,39 +58,40 @@ module ZuoraConnect
|
|
76
58
|
msg = JSON.parse(msg)
|
77
59
|
rescue JSON::ParserError => ex
|
78
60
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
61
|
+
|
62
|
+
require 'json'
|
63
|
+
store = {
|
64
|
+
name: name,
|
65
|
+
level: serverity,
|
66
|
+
timestamp: datetime.strftime('%FT%T.%6NZ'),
|
67
|
+
pid: Process.pid,
|
68
|
+
message: name == "ActionMailer" ? msg.strip : msg
|
69
|
+
}
|
70
|
+
if !['ElasticAPM', 'ResqueScheduler', 'ResquePool','Resque', 'Makara'].include?(name)
|
71
|
+
if Thread.current[:appinstance].present?
|
72
|
+
store[:app_instance_id] = Thread.current[:appinstance].id
|
73
|
+
logitems = Thread.current[:appinstance].logitems
|
74
|
+
if logitems.present? && logitems.class == Hash
|
75
|
+
store[:tenant_ids] = logitems[:tenant_ids] if logitems[:tenant_ids].present?
|
76
|
+
store[:organization] = logitems[:organization] if logitems[:organization].present?
|
96
77
|
end
|
97
78
|
end
|
98
|
-
JSON.dump(store) + "\n"
|
99
|
-
else
|
100
|
-
format('%s %s: %s', serverity.ljust(6), datetime, msg) + "\n"
|
101
79
|
end
|
80
|
+
JSON.dump(store) + "\n"
|
102
81
|
end
|
103
82
|
end
|
104
83
|
return logger
|
105
|
-
end
|
84
|
+
end
|
106
85
|
end
|
107
86
|
|
108
87
|
module Controllers
|
109
88
|
autoload :Helpers, 'zuora_connect/controllers/helpers'
|
110
89
|
end
|
111
90
|
|
91
|
+
module Views
|
92
|
+
ActionView::Base.send(:include, Helpers)
|
93
|
+
end
|
94
|
+
|
112
95
|
def self.configuration
|
113
96
|
@configuration ||= Configuration.new
|
114
97
|
end
|
@@ -146,23 +129,23 @@ module ZuoraConnect
|
|
146
129
|
}
|
147
130
|
when 'test'
|
148
131
|
defaults = {
|
149
|
-
active: false,
|
132
|
+
active: false,
|
150
133
|
disable_send: true
|
151
134
|
}
|
152
135
|
end
|
153
136
|
|
154
137
|
defaults.merge!({
|
155
138
|
disable_start_message: true,
|
156
|
-
pool_size: 1,
|
157
|
-
transaction_max_spans: 500,
|
158
|
-
ignore_url_patterns: ['^\/admin\/resque.*', '^\/admin\/redis.*', '^\/admin\/peek.*', '^\/peek.*'],
|
139
|
+
pool_size: 1,
|
140
|
+
transaction_max_spans: 500,
|
141
|
+
ignore_url_patterns: ['^\/admin\/resque.*', '^\/admin\/redis.*', '^\/admin\/peek.*', '^\/peek.*'],
|
159
142
|
verify_server_cert: false,
|
160
143
|
log_level: Logger::INFO,
|
161
144
|
service_name: ENV['DEIS_APP'].present? ? ENV['DEIS_APP'] : Rails.application.class.parent_name,
|
162
145
|
logger: ZuoraConnect.custom_logger(name: "ElasticAPM", level: MonoLogger::WARN)
|
163
146
|
})
|
164
147
|
defaults.merge!({disable_send: true}) if defined?(Rails::Console)
|
165
|
-
|
148
|
+
|
166
149
|
return defaults
|
167
150
|
end
|
168
151
|
end
|
@@ -3,11 +3,11 @@ module ZuoraConnect
|
|
3
3
|
|
4
4
|
attr_accessor :default_locale, :default_time_zone, :url, :mode, :delayed_job,:private_key, :additional_apartment_models
|
5
5
|
|
6
|
-
attr_accessor :enable_metrics, :telegraf_endpoint, :telegraf_debug, :custom_prometheus_update_block, :silencer_resque_finish, :blpop_queue
|
6
|
+
attr_accessor :enable_metrics, :telegraf_endpoint, :telegraf_debug, :custom_prometheus_update_block, :silencer_resque_finish, :blpop_queue, :app_access_permissions
|
7
7
|
|
8
8
|
attr_accessor :oauth_client_id, :oauth_client_secret, :oauth_client_redirect_uri
|
9
9
|
|
10
|
-
attr_accessor :dev_mode_logins, :dev_mode_options, :dev_mode_mode, :dev_mode_appinstance, :dev_mode_user, :dev_mode_pass, :dev_mode_admin, :dev_mode_secret_access_key,:dev_mode_access_key_id,:aws_region, :s3_bucket_name, :s3_folder_name
|
10
|
+
attr_accessor :dev_mode_logins, :dev_mode_options, :dev_mode_mode, :dev_mode_appinstance, :dev_mode_user, :dev_mode_pass, :dev_mode_admin, :dev_mode_secret_access_key,:dev_mode_access_key_id,:aws_region, :s3_bucket_name, :s3_folder_name
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
@default_locale = :en
|
@@ -19,6 +19,7 @@ module ZuoraConnect
|
|
19
19
|
@additional_apartment_models = []
|
20
20
|
@silencer_resque_finish = true
|
21
21
|
@blpop_queue = false
|
22
|
+
@app_access_permissions = false
|
22
23
|
|
23
24
|
# Setting the app name for telegraf write
|
24
25
|
@enable_metrics = false
|
@@ -42,7 +43,6 @@ module ZuoraConnect
|
|
42
43
|
@aws_region = "us-west-2"
|
43
44
|
@s3_bucket_name = "rbm-apps"
|
44
45
|
@s3_folder_name = Rails.application.class.parent_name
|
45
|
-
@json_logging = Rails.env.to_s == 'development' ? false : true
|
46
46
|
end
|
47
47
|
|
48
48
|
def private_key
|
@@ -16,7 +16,7 @@ module ZuoraConnect
|
|
16
16
|
ZuoraConnect.logger.debug("[#{@appinstance.id}] API REQUEST - API token") if @appinstance.present?
|
17
17
|
check_instance
|
18
18
|
elsif ZuoraConnect::AppInstance::INTERNAL_HOSTS.include?(request.headers.fetch("HOST", nil))
|
19
|
-
zuora_host, zuora_entity_id, zuora_instance_id = [request.headers['zuora-host'],
|
19
|
+
zuora_host, zuora_entity_id, zuora_instance_id = [request.headers['zuora-host'], request.headers['zuora-entity-ids'].gsub('-',''), request.headers['zuora-instance-id']]
|
20
20
|
|
21
21
|
#Validate host present
|
22
22
|
if zuora_host.blank?
|
@@ -37,24 +37,21 @@ module ZuoraConnect
|
|
37
37
|
|
38
38
|
if appinstances.size == 0
|
39
39
|
render json: {"status": 401, "message": "Missing mapping or no deployment for '#{zuora_host}-#{zuora_entity_id}' ."}, status: :unauthorized
|
40
|
-
return
|
41
40
|
elsif appinstances.size > 1
|
42
41
|
render json: {"status": 401, "message": "More than one app instance binded to host and entity ids. Please indicate correct instance via 'zuora-instance-id' header"}, status: :unauthorized
|
43
|
-
return
|
44
42
|
else
|
45
43
|
@appinstance = appinstances.first
|
46
|
-
check_instance
|
47
44
|
end
|
48
|
-
|
49
|
-
|
45
|
+
|
46
|
+
else #if request.headers.fetch("Authorization", "").include?("Basic ")
|
50
47
|
authenticate_or_request_with_http_basic do |username, password|
|
51
48
|
@appinstance = ZuoraConnect::AppInstance.where(:token => password).first
|
52
49
|
@appinstance ||= ZuoraConnect::AppInstance.where(:api_token => password).first
|
53
50
|
ZuoraConnect.logger.debug("[#{@appinstance.id}] API REQUEST - Basic Auth") if @appinstance.present?
|
54
51
|
check_instance
|
55
52
|
end
|
56
|
-
else
|
57
|
-
|
53
|
+
# else
|
54
|
+
# check_instance
|
58
55
|
end
|
59
56
|
|
60
57
|
if @appinstance.present?
|
@@ -62,253 +59,175 @@ module ZuoraConnect
|
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
|
-
#API ONLY
|
66
|
-
def check_instance
|
67
|
-
if defined?(@appinstance) && @appinstance.present?
|
68
|
-
if @appinstance.new_session_for_api_requests(:params => params)
|
69
|
-
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
|
70
|
-
end
|
71
|
-
Thread.current[:appinstance] = @appinstance
|
72
|
-
PaperTrail.whodunnit = "API User" if defined?(PaperTrail)
|
73
|
-
ElasticAPM.set_user("API User") if defined?(ElasticAPM) && ElasticAPM.running?
|
74
|
-
return true
|
75
|
-
else
|
76
|
-
response.set_header('WWW-Authenticate', "Basic realm=\"Application\"")
|
77
|
-
render json: {"status": 401, "message": "Access Denied"}, status: :unauthorized
|
78
|
-
return false
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
62
|
def authenticate_connect_app_request
|
83
63
|
ElasticAPM.set_tag(:trace_id, request.uuid) if defined?(ElasticAPM) && ElasticAPM.running?
|
84
64
|
Thread.current[:appinstance] = nil
|
85
|
-
start_time = Time.now
|
86
65
|
|
87
|
-
if
|
88
|
-
|
66
|
+
if request.headers['ZuoraCurrentEntity'].present?
|
67
|
+
|
68
|
+
#Do we need to refresh session identity
|
69
|
+
zuora_host = request.headers["HTTP_X_FORWARDED_HOST"] || "apisandbox.zuora.com"
|
70
|
+
if request.headers["Zuora-Auth-Token"].present?
|
71
|
+
zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", bearer_token: request.headers["Zuora-Auth-Token"], oauth_session_expires_at: Time.now + 5.minutes )
|
72
|
+
elsif cookies['ZSession'].present?
|
73
|
+
zuora_client = ZuoraAPI::Basic.new(url: "https://#{zuora_host}", session: cookies['ZSession'])
|
74
|
+
else
|
75
|
+
raise ZuoraConnect::Exceptions::Error.new("Neither the ZSession cookie nor the Zuora-Auth-Token are present in payload.")
|
76
|
+
end
|
77
|
+
zuora_entity_id = request.headers['ZuoraCurrentEntity']
|
78
|
+
zuora_instance_id = params[:sidebar_launch].to_bool ? nil : (params[:app_instance_id] || session["appInstance"])
|
89
79
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
80
|
+
#Identity blank or current entity different
|
81
|
+
if (session["ZuoraCurrentIdentity"].blank? || session["ZuoraCurrentEntity"] != zuora_entity_id)
|
82
|
+
begin
|
83
|
+
identity, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("identity"))
|
84
|
+
session["ZuoraCurrentIdentity"] = identity
|
85
|
+
session["ZuoraCurrentEntity"] = identity['entityId']
|
94
86
|
|
95
|
-
|
87
|
+
raise ZuoraConnect::Exceptions::Error.new("Header entity id, '#{zuora_entity_id}' does not match identity call entity id, '#{identity['entityId']}'.") if zuora_entity_id != identity['entityId']
|
88
|
+
rescue => ex
|
89
|
+
ZuoraConnect.logger.error(ex)
|
90
|
+
render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
|
91
|
+
return
|
92
|
+
end
|
93
|
+
end
|
96
94
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
#Find matching app instances.
|
96
|
+
if zuora_instance_id.present?
|
97
|
+
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host AND id = :id", entities: [zuora_entity_id], host: zuora_client.rest_domain, id: zuora_instance_id).pluck(:id, :name)
|
98
|
+
else
|
99
|
+
#if app_instance_ids is present then permissions still controlled by connect
|
100
|
+
if params[:app_instance_ids].present?
|
101
|
+
begin
|
102
|
+
navbar, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("navigation"))
|
103
|
+
urls = navbar['menus'].map {|x| x['url']}
|
104
|
+
app_env = ENV["DEIS_APP"] || "xyz123"
|
105
|
+
url = urls.compact.select {|url| File.basename(url).start_with?(app_env + '?')}.first
|
106
|
+
task_ids = JSON.parse(Base64.urlsafe_decode64(CGI.parse(URI.parse(url).query)["app_instance_ids"][0]))
|
107
|
+
|
108
|
+
appinstances = ZuoraConnect::AppInstance.where(:id => task_ids).pluck(:id, :name)
|
109
|
+
rescue => ex
|
110
|
+
ZuoraConnect.logger.error(ex)
|
111
|
+
render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
|
112
|
+
return
|
113
|
+
end
|
102
114
|
else
|
103
|
-
|
104
|
-
:title => "Missing Authorization Token",
|
105
|
-
:message => "Zuora 'Zuora-Auth-Token' header and 'ZSession' cookie not present."
|
106
|
-
}, :layout => false
|
107
|
-
return
|
115
|
+
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host", entities: [zuora_entity_id], host: zuora_client.rest_domain).pluck(:id, :name)
|
108
116
|
end
|
117
|
+
end
|
109
118
|
|
110
|
-
|
111
|
-
zuora_instance_id = params[:sidebar_launch].to_s.to_bool ? nil : (params[:app_instance_id] || session["appInstance"])
|
112
|
-
|
113
|
-
#Identity blank or current entity different
|
114
|
-
different_zsession = session["ZSession"] != cookies['ZSession']
|
115
|
-
missmatched_entity = session["ZuoraCurrentEntity"] != zuora_entity_id
|
116
|
-
missing_identity = session["ZuoraCurrentIdentity"].blank?
|
119
|
+
zuora_user_id = cookies['Zuora-User-Id'] || session["ZuoraCurrentIdentity"]['userId']
|
117
120
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
session["ZuoraCurrentIdentity"] = identity
|
122
|
-
session["ZuoraCurrentEntity"] = identity['entityId']
|
123
|
-
session["ZSession"] = cookies['ZSession']
|
124
|
-
zuora_instance_id = nil
|
125
|
-
zuora_details["identity"]["entityId"] = identity['entityId']
|
121
|
+
#One deployed instance
|
122
|
+
if appinstances.size == 1
|
123
|
+
ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
|
126
124
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
125
|
+
#Add user/update
|
126
|
+
@user = ZuoraConnect::ZuoraUser.where(:zuora_user_id => zuora_user_id).first
|
127
|
+
if @user.present?
|
128
|
+
ZuoraConnect.logger.debug("Current zuora user #{zuora_user_id}")
|
129
|
+
if @user.updated_at < Time.now - 1.day
|
130
|
+
@user.zuora_identity_response[zuora_entity_id] = session["ZuoraCurrentIdentity"]
|
131
|
+
@user.save!
|
131
132
|
end
|
133
|
+
else
|
134
|
+
ZuoraConnect.logger.debug("New zuora user object for #{zuora_user_id}")
|
135
|
+
@user = ZuoraConnect::ZuoraUser.create!(:zuora_user_id => zuora_user_id, :zuora_identity_response => {zuora_entity_id => session["ZuoraCurrentIdentity"]})
|
136
|
+
end
|
137
|
+
#Update access if admin in tenant
|
138
|
+
if session["ZuoraCurrentIdentity"]['platformRole'] == 'ADMIN' && !@user.app_permissions['access'].to_bool
|
139
|
+
@user.app_permissions['access'] = true
|
140
|
+
@user.save!
|
141
|
+
end
|
132
142
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
143
|
+
#If user has has access to application
|
144
|
+
if @user.app_permissions['access'].to_bool || !ZuoraConnect.configuration.app_access_permissions
|
145
|
+
session["appInstance"] = appinstances.to_h.keys.first
|
146
|
+
else
|
147
|
+
Thread.current[:appinstance] = nil
|
148
|
+
session["appInstance"] = nil
|
149
|
+
admin_users = ZuoraConnect::ZuoraUser.select("zuora_identity_response #>> '{#{zuora_entity_id},username}' as username").where("zuora_identity_response #>> :selector = 'ADMIN' ", :selector => "{#{zuora_entity_id},platformRole}")
|
150
|
+
render "zuora_connect/static/permission_error", :locals => {:admins => admin_users}
|
151
|
+
return
|
152
|
+
end
|
153
|
+
#We have multiple, user must pick
|
154
|
+
elsif appinstances.size > 1
|
155
|
+
ZuoraConnect.logger.debug("User must select instance. #{@names}")
|
156
|
+
render "zuora_connect/static/launch", :locals => {:names => appinstances.to_h}
|
157
|
+
return
|
158
|
+
else
|
159
|
+
begin
|
160
|
+
#Ensure user can access oauth creation API
|
161
|
+
if session["ZuoraCurrentIdentity"]['platformRole'] != 'ADMIN'
|
162
|
+
raise ZuoraConnect::Exceptions::Error.new("User is not admin, workflow cannot be deployed.")
|
149
163
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
session["#{@appinstance.id}::user::locale"] = session['ZuoraCurrentIdentity']["language"]
|
174
|
-
session["appInstance"] = @appinstance.id
|
175
|
-
|
176
|
-
#We have multiple, user must pick
|
177
|
-
elsif appinstances.size > 1
|
178
|
-
ZuoraConnect.logger.debug("User must select instance. #{@names}")
|
179
|
-
render "zuora_connect/static/launch", :locals => {:names => appinstances.to_h}, :layout => false
|
180
|
-
return
|
181
|
-
|
182
|
-
#We have no deployed instance for this tenant
|
183
|
-
else
|
184
|
-
#Ensure user can access oauth creation API
|
185
|
-
if session["ZuoraCurrentIdentity"]['platformRole'] != 'ADMIN'
|
186
|
-
Thread.current[:appinstance] = nil
|
187
|
-
session["appInstance"] = nil
|
188
|
-
render "zuora_connect/static/error_handled", :locals => {
|
189
|
-
:title => "Application can only complete its initial setup via platform administrator",
|
190
|
-
:message => "Please contact admin of tenant and have them click on link again to launch application."
|
191
|
-
}, :layout => false
|
192
|
-
return
|
193
|
-
end
|
194
|
-
Apartment::Tenant.switch!("public")
|
195
|
-
ActiveRecord::Base.transaction do
|
196
|
-
ActiveRecord::Base.connection.execute('LOCK public.zuora_users IN ACCESS EXCLUSIVE MODE')
|
197
|
-
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host", entities: [zuora_entity_id], host: zuora_client.rest_domain).pluck(:id, :name)
|
198
|
-
|
199
|
-
if appinstances.size > 0
|
200
|
-
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
|
201
|
-
return
|
202
|
-
end
|
203
|
-
|
204
|
-
next_id = (ZuoraConnect::AppInstance.all.where('id > 24999999').order(id: :desc).limit(1).pluck(:id).first || 24999999) + 1
|
205
|
-
user = (ENV['DEIS_APP'] || "Application").split('-').map(&:capitalize).join(' ')
|
206
|
-
body = {
|
207
|
-
'userId' => zuora_user_id,
|
208
|
-
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
|
209
|
-
'customAuthorities' => [],
|
210
|
-
'additionalInformation' => {
|
211
|
-
'description' => "This user is for #{user} application.",
|
212
|
-
'name' => "#{user} API User #{next_id}"
|
213
|
-
}
|
214
|
-
}
|
215
|
-
|
216
|
-
oauth_response, response = zuora_client.rest_call(method: :post, body: body.to_json, url: zuora_client.rest_endpoint("genesis/clients").gsub('v1/', ''), session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic, headers: zuora_client.class == ZuoraAPI::Oauth ? {} : {'Authorization' => "ZSession-a3N2w #{zuora_client.get_session(prefix: false, auth_type: :basic)}"})
|
217
|
-
|
218
|
-
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
219
|
-
if session["ZuoraCurrentUserInfo"].blank?
|
220
|
-
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
221
|
-
else
|
222
|
-
client_describe = session["ZuoraCurrentUserInfo"]
|
223
|
-
end
|
224
|
-
|
225
|
-
available_entities = client_describe["accessibleEntities"].select {|entity| entity['id'] == zuora_entity_id}
|
226
|
-
task_data = {
|
227
|
-
"id": next_id,
|
228
|
-
"name": client_describe["tenantName"],
|
229
|
-
"mode": "Collections",
|
230
|
-
"status": "Running",
|
231
|
-
ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION => {
|
232
|
-
"tenant_type": "Zuora",
|
233
|
-
"username": session["ZuoraCurrentIdentity"]["username"],
|
234
|
-
"url": new_zuora_client.url,
|
235
|
-
"status": "Active",
|
236
|
-
"oauth_client_id": oauth_response['clientId'],
|
237
|
-
"oauth_secret": oauth_response['clientSecret'],
|
238
|
-
"authentication_type": "OAUTH",
|
239
|
-
"entities": available_entities.map {|e| e.merge({'displayName' => client_describe["tenantName"]})}
|
240
|
-
},
|
241
|
-
"tenant_ids": available_entities.map{|e| e['entityId']}.uniq,
|
242
|
-
}
|
243
|
-
mapped_values = {:id => next_id, :api_token => rand(36**64).to_s(36), :token => rand(36**64).to_s(36), :zuora_logins => task_data, :oauth_expires_at => Time.now + 1000.years, :zuora_domain => zuora_client.rest_domain, :zuora_entity_ids => [zuora_entity_id]}
|
244
|
-
@appinstance = ZuoraConnect::AppInstance.new(mapped_values)
|
245
|
-
retry_count = 0
|
246
|
-
begin
|
247
|
-
@appinstance.save(:validate => false)
|
248
|
-
rescue ActiveRecord::RecordNotUnique => ex
|
249
|
-
if (retry_count += 1) < 3
|
250
|
-
@appinstance.assign_attributes({:api_token => rand(36**64).to_s(36), :token => rand(36**64).to_s(36)})
|
251
|
-
retry
|
252
|
-
else
|
253
|
-
Thread.current[:appinstance] = nil
|
254
|
-
session["appInstance"] = nil
|
255
|
-
render "zuora_connect/static/error_handled", :locals => {
|
256
|
-
:title => "Application could not create unique tokens.",
|
257
|
-
:message => "Please contact support or retry launching application."
|
258
|
-
}, :layout => false
|
259
|
-
return
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
Apartment::Tenant.switch!("public")
|
265
|
-
begin
|
266
|
-
Apartment::Tenant.create(@appinstance.id.to_s)
|
267
|
-
rescue Apartment::TenantExists => ex
|
268
|
-
ZuoraConnect.logger.debug("Tenant Already Exists")
|
269
|
-
end
|
270
|
-
@appinstance.refresh
|
271
|
-
session["appInstance"] = @appinstance.id
|
164
|
+
|
165
|
+
body = {
|
166
|
+
'userId' => zuora_user_id,
|
167
|
+
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
|
168
|
+
'customAuthorities' => [],
|
169
|
+
'additionalInformation' => {
|
170
|
+
'description' => 'This user is for workflow application.',
|
171
|
+
'name' => 'Workflow API User'
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
oauth_response, response = zuora_client.rest_call(method: :post, body: body.to_json, url: zuora_client.rest_endpoint("genesis/clients").gsub('v1/', ''), session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic, headers: zuora_client.class == ZuoraAPI::Oauth ? {} : {'Authorization' => "ZSession-a3N2w #{zuora_client.get_session(prefix: false, auth_type: :basic)}"})
|
176
|
+
|
177
|
+
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
178
|
+
|
179
|
+
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
180
|
+
|
181
|
+
Apartment::Tenant.switch!("public")
|
182
|
+
next_id = (ZuoraConnect::AppInstance.all.where(:access_token => nil).order(id: :desc).limit(1).pluck(:id).first || 24999999) + 1
|
183
|
+
begin
|
184
|
+
Apartment::Tenant.create(next_id.to_s)
|
185
|
+
rescue Apartment::TenantExists => ex
|
186
|
+
ZuoraConnect.logger.debug("Tenant Already Exists")
|
272
187
|
end
|
273
188
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
189
|
+
task_data = {
|
190
|
+
"id": next_id,
|
191
|
+
"name": client_describe["tenantName"],
|
192
|
+
"mode": "Collections",
|
193
|
+
"status": "Running",
|
194
|
+
"target_login": {
|
195
|
+
"tenant_type": "Zuora",
|
196
|
+
"username": session["ZuoraCurrentIdentity"]["username"],
|
197
|
+
"url": new_zuora_client.url,
|
198
|
+
"status": "Active",
|
199
|
+
"oauth_client_id": oauth_response['clientId'],
|
200
|
+
"oauth_secret": oauth_response['clientSecret'],
|
201
|
+
"authentication_type": "OAUTH",
|
202
|
+
"entities": client_describe["accessibleEntities"].map {|e| e.merge({'displayName' => client_describe["tenantName"]})} #needs work
|
203
|
+
},
|
204
|
+
"tenant_ids": client_describe["accessibleEntities"].map{|e| e['entityId'] }.push(client_describe["tenantId"]).uniq,
|
205
|
+
}
|
206
|
+
|
207
|
+
appinstance = ZuoraConnect::AppInstance.new(:id => next_id, :zuora_logins => task_data.to_json, :oauth_expires_at => Time.now + 1000.years)
|
208
|
+
appinstance.save(:validate => false)
|
209
|
+
@appinstance = ZuoraConnect::AppInstance.find(appinstance.id)
|
210
|
+
@appinstance.apartment_switch(method = nil, migrate = true)
|
211
|
+
|
212
|
+
session["appInstance"] = @appinstance.id
|
283
213
|
rescue => ex
|
284
|
-
ZuoraConnect.logger.error(ex
|
285
|
-
render "zuora_connect/static/
|
286
|
-
return
|
214
|
+
ZuoraConnect.logger.error(ex)
|
215
|
+
render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
|
216
|
+
return
|
287
217
|
end
|
288
|
-
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
start_time = Time.now
|
222
|
+
if ZuoraConnect.configuration.mode == "Production"
|
223
|
+
if request["data"] && /^([A-Za-z0-9+\/\-\_]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/.match(request["data"].to_s)
|
289
224
|
setup_instance_via_data
|
290
225
|
else
|
291
|
-
|
292
|
-
@appinstance = ZuoraConnect::AppInstance.where(:id => session["appInstance"]).first
|
293
|
-
else
|
294
|
-
render "zuora_connect/static/error_handled", :locals => {
|
295
|
-
:title => "Application state could not be verified",
|
296
|
-
:message => "Please relaunch application."
|
297
|
-
}, :layout => false
|
298
|
-
return
|
299
|
-
end
|
226
|
+
setup_instance_via_session
|
300
227
|
end
|
301
228
|
else
|
302
229
|
setup_instance_via_dev_mode
|
303
230
|
end
|
304
|
-
|
305
|
-
if !defined?(@appinstance) || @appinstance.blank?
|
306
|
-
render "zuora_connect/static/error_handled", :locals => {
|
307
|
-
:title => "Application state could not be found.",
|
308
|
-
:message => "Please relaunch application."
|
309
|
-
}, :layout => false
|
310
|
-
return
|
311
|
-
end
|
312
231
|
#Call .data_lookup with the current session to retrieve session. In some cases session may be stored/cache in redis
|
313
232
|
#so data lookup provides a model method that can be overriden per app.
|
314
233
|
if params[:controller] != 'zuora_connect/api/v1/app_instance' && params[:action] != 'drop'
|
@@ -316,23 +235,16 @@ module ZuoraConnect
|
|
316
235
|
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
|
317
236
|
end
|
318
237
|
end
|
319
|
-
|
320
238
|
if session["#{@appinstance.id}::user::email"].present?
|
321
239
|
ElasticAPM.set_user(session["#{@appinstance.id}::user::email"]) if defined?(ElasticAPM) && ElasticAPM.running?
|
322
240
|
PaperTrail.whodunnit = session["#{@appinstance.id}::user::email"] if defined?(PaperTrail)
|
323
241
|
end
|
324
242
|
begin
|
325
|
-
locale = session["#{@appinstance.id}::user::locale"]
|
326
|
-
I18n.locale = locale.present? ? locale : @appinstance.locale
|
243
|
+
I18n.locale = session["#{@appinstance.id}::user::locale"] ? session["#{@appinstance.id}::user::locale"] : @appinstance.locale
|
327
244
|
rescue I18n::InvalidLocale => ex
|
328
245
|
ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
329
246
|
end
|
330
|
-
|
331
|
-
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
332
|
-
rescue
|
333
|
-
ZuoraConnect.logger.error(ex)
|
334
|
-
end
|
335
|
-
|
247
|
+
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
336
248
|
ZuoraConnect.logger.debug("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App Request Completed In - #{(Time.now - start_time).round(2)}s")
|
337
249
|
end
|
338
250
|
|
@@ -354,14 +266,6 @@ module ZuoraConnect
|
|
354
266
|
return session["#{@appinstance.id}::admin"]
|
355
267
|
end
|
356
268
|
|
357
|
-
def zuora_user
|
358
|
-
return @zuora_user
|
359
|
-
end
|
360
|
-
|
361
|
-
def hallway_integration?
|
362
|
-
return (request.headers['ZuoraCurrentEntity'].present? || cookies['ZuoraCurrentEntity'].present?)
|
363
|
-
end
|
364
|
-
|
365
269
|
private
|
366
270
|
def setup_instance_via_data
|
367
271
|
session.clear
|
@@ -383,7 +287,6 @@ module ZuoraConnect
|
|
383
287
|
ZuoraConnect.logger.debug({msg: 'Setup values', connect: values}) if Rails.env != "production"
|
384
288
|
|
385
289
|
@appinstance = ZuoraConnect::AppInstance.where(:id => values["appInstance"].to_i).first
|
386
|
-
|
387
290
|
if @appinstance.blank?
|
388
291
|
Apartment::Tenant.switch!("public")
|
389
292
|
begin
|
@@ -391,20 +294,29 @@ module ZuoraConnect
|
|
391
294
|
rescue Apartment::TenantExists => ex
|
392
295
|
ZuoraConnect.logger.debug("Tenant Already Exists")
|
393
296
|
end
|
394
|
-
|
395
|
-
@appinstance = ZuoraConnect::AppInstance.new(mapped_values.merge({:id => values["appInstance"].to_i}))
|
297
|
+
@appinstance = ZuoraConnect::AppInstance.new(:api_token => values[:api_token],:id => values["appInstance"].to_i, :access_token => values["access_token"].blank? ? values["user"] : values["access_token"], :token => values["refresh_token"] , :refresh_token => values["refresh_token"].blank? ? values["key"] : values["refresh_token"], :oauth_expires_at => values["expires"])
|
396
298
|
@appinstance.save(:validate => false)
|
397
299
|
else
|
398
|
-
|
399
|
-
@appinstance.
|
300
|
+
@appinstance.access_token = values["access_token"] if !values["access_token"].blank? && @appinstance.access_token != values["access_token"]
|
301
|
+
@appinstance.refresh_token = values["refresh_token"] if !values["refresh_token"].blank? && @appinstance.refresh_token != values["refresh_token"]
|
302
|
+
@appinstance.oauth_expires_at = values["expires"] if !values["expires"].blank?
|
303
|
+
@appinstance.api_token = values["api_token"] if !values["api_token"].blank? && @appinstance.api_token != values["api_token"]
|
400
304
|
if @appinstance.access_token_changed? && @appinstance.refresh_token_changed?
|
401
305
|
@appinstance.save(:validate => false)
|
402
306
|
else
|
403
|
-
raise ZuoraConnect::Exceptions::AccessDenied.new("Authorization
|
307
|
+
raise ZuoraConnect::Exceptions::AccessDenied.new("Authorization mistmatch. Possible tampering")
|
404
308
|
end
|
405
309
|
end
|
406
310
|
end
|
407
311
|
|
312
|
+
def setup_instance_via_session
|
313
|
+
if session["appInstance"].present?
|
314
|
+
@appinstance = ZuoraConnect::AppInstance.where(:id => session["appInstance"]).first
|
315
|
+
else
|
316
|
+
raise ZuoraConnect::Exceptions::SessionInvalid.new("Session Blank -- Relaunch Application")
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
408
320
|
def setup_instance_via_dev_mode
|
409
321
|
session["appInstance"] = ZuoraConnect.configuration.dev_mode_appinstance
|
410
322
|
user = ZuoraConnect.configuration.dev_mode_user
|
@@ -428,6 +340,24 @@ module ZuoraConnect
|
|
428
340
|
end
|
429
341
|
session["#{@appinstance.id}::admin"] = ZuoraConnect.configuration.dev_mode_admin
|
430
342
|
end
|
343
|
+
|
344
|
+
#API ONLY
|
345
|
+
def check_instance
|
346
|
+
if defined?(@appinstance) && @appinstance.present?
|
347
|
+
if @appinstance.new_session_for_api_requests(:params => params)
|
348
|
+
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
|
349
|
+
end
|
350
|
+
Thread.current[:appinstance] = @appinstance
|
351
|
+
PaperTrail.whodunnit = "API User" if defined?(PaperTrail)
|
352
|
+
ElasticAPM.set_user("API User") if defined?(ElasticAPM) && ElasticAPM.running?
|
353
|
+
return true
|
354
|
+
else
|
355
|
+
response.set_header('WWW-Authenticate', "Basic realm=\"Application\"")
|
356
|
+
#render json: {"status": 401, "message": "Access Denied"}, status: :unauthorized
|
357
|
+
render html: "HTTP Basic: Access denied.\n", status: :unauthorized
|
358
|
+
render plain: "Access Denied", status: :unauthorized
|
359
|
+
end
|
360
|
+
end
|
431
361
|
end
|
432
362
|
end
|
433
363
|
end
|