require 'apartment/migrator'
module ZuoraConnect
module Controllers
module Helpers
extend ActiveSupport::Concern
def authenticate_app_api_request
ZuoraConnect::AppInstance.read_master_db do
#Skip session for api requests
request.session_options[:skip] = true
Thread.current[:appinstance] = nil
if ZuoraConnect.logger.is_a?(Ougai::Logger); ZuoraConnect.logger.with_fields = {}; end
if Rails.logger.is_a?(Ougai::Logger); Rails.logger.with_fields = {}; end
if defined?(ElasticAPM) && ElasticAPM.running?
if ElasticAPM.respond_to?(:set_label)
ElasticAPM.set_label(:trace_id, request.uuid) if defined?(ElasticAPM) && ElasticAPM.running?
else
ElasticAPM.set_label(:trace_id, request.uuid) if defined?(ElasticAPM) && ElasticAPM.running?
end
end
if request.headers["API-Token"].present?
@appinstance = ZuoraConnect::AppInstance.find_by(:api_token => request.headers["API-Token"])
ZuoraConnect.logger.debug("API REQUEST - API token") if @appinstance.present?
check_instance
elsif ZuoraConnect::AppInstance::INTERNAL_HOSTS.include?(request.headers.fetch("HOST", nil))
zuora_host, zuora_entity_id, zuora_instance_id = [request.headers['zuora-host'], (request.headers['zuora-entity-ids'] || "").gsub('-',''), request.headers['zuora-instance-id']]
#Validate host present
if zuora_host.blank?
render json: {"status": 401, "message": "zuora-host header was not supplied."}, status: :unauthorized
return
end
#Validate entity-ids present
if zuora_entity_id.blank?
render json: {"status": 401, "message": "zuora-entity-ids header was not supplied."}, status: :unauthorized
return
end
#Select with instance id if present. Used where mulitple deployments are done.
if zuora_instance_id.present?
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host AND id = :id", entities: [zuora_entity_id], host: zuora_host, id: zuora_instance_id.to_i)
else
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host", entities: [zuora_entity_id], host: zuora_host)
end
if appinstances.size == 0
render json: {"status": 401, "message": "Missing mapping or no deployment for '#{zuora_host}-#{zuora_entity_id}' ."}, status: :unauthorized
return
elsif appinstances.size > 1
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", "instances": appinstances.map {|instance| instance.id }.sort }, status: :unauthorized
return
else
@appinstance = appinstances.first
check_instance
end
elsif request.headers.fetch("Authorization", "").include?("Basic ")
authenticate_or_request_with_http_basic do |username, password|
@appinstance = ZuoraConnect::AppInstance.find_by(:token => password)
@appinstance ||= ZuoraConnect::AppInstance.find_by(:api_token => password)
ZuoraConnect.logger.debug("API REQUEST - Basic Auth") if @appinstance.present?
check_instance
end
else
check_instance
end
end
end
#API ONLY
def check_instance
if defined?(@appinstance) && @appinstance.present?
if @appinstance.new_session_for_api_requests(:params => params)
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
end
Thread.current[:appinstance] = @appinstance
PaperTrail.whodunnit = "API User" if defined?(PaperTrail)
ElasticAPM.set_user("API User") if defined?(ElasticAPM) && ElasticAPM.running?
return true
else
response.set_header('WWW-Authenticate', "Basic realm=\"Application\"")
render json: {"status": 401, "message": "Access Denied"}, status: :unauthorized
return false
end
end
def authenticate_connect_app_request
ZuoraConnect::AppInstance.read_master_db do
Thread.current[:appinstance] = nil
if ZuoraConnect.logger.is_a?(Ougai::Logger); ZuoraConnect.logger.with_fields = {}; end
if Rails.logger.is_a?(Ougai::Logger); Rails.logger.with_fields = {}; end
if defined?(ElasticAPM) && ElasticAPM.running?
if ElasticAPM.respond_to?(:set_label)
ElasticAPM.set_label(:trace_id, request.uuid)
else
ElasticAPM.set_label(:trace_id, request.uuid)
end
end
if ZuoraConnect.configuration.mode == "Production"
setup_instance_via_prod_mode
else
setup_instance_via_dev_mode
end
return if performed?
if !defined?(@appinstance) || @appinstance.blank?
render "zuora_connect/static/error_handled", :locals => {
:title => "Application state could not be found.",
:message => "Please relaunch application."
}, :layout => false
return
end
#Call .data_lookup with the current session to retrieve session. In some cases session may be stored/cache in redis
#so data lookup provides a model method that can be overriden per app.
if params[:controller] != 'zuora_connect/api/v1/app_instance' && params[:action] != 'drop'
if @appinstance.new_session_for_ui_requests(:params => params)
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
end
end
if session["#{@appinstance.id}::user::email"].present?
ElasticAPM.set_user(session["#{@appinstance.id}::user::email"]) if defined?(ElasticAPM) && ElasticAPM.running?
PaperTrail.whodunnit = session["#{@appinstance.id}::user::email"] if defined?(PaperTrail)
end
begin
locale = session["#{@appinstance.id}::user::locale"]
I18n.locale = locale.present? ? locale : @appinstance.locale
rescue I18n::InvalidLocale => ex
ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
end
begin
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
rescue
ZuoraConnect.logger.error(ex)
end
end
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
id = @appinstance.id
ZuoraConnect::AppInstance.destroy(id)
Apartment::Tenant.drop(id)
render "zuora_connect/static/error_handled", :locals => {
:title => "Application Setup Error",
:message => "Application cannot be run using Zuora Session. Delete old application \
deployment and create new with Zuora Basic or OAuth credentials."
}, :layout => false
return
rescue ZuoraConnect::Exceptions::AccessDenied => ex
respond_to do |format|
format.html {
render "zuora_connect/static/error_handled", :locals => {
:title => "Application State Error",
:message => ex.message
}, status: 401, layout: false
}
format.js {
render "zuora_connect/static/error_handled", :locals => {
:title => "Application State Error",
:message => ex.message
}, status: 401, layout: false
}
format.json { render json: {'errors' => ex.message}, status: 401 }
format.all { render json: ex.message, status: 401 }
end
return
rescue => ex
ZuoraConnect.logger.error("UI Authorization Error", ex)
respond_to do |format|
format.html { render 'zuora_connect/static/error_unhandled', :locals => {:exception => ex, :skip_exception => true}, status: 500, layout: false }
format.js { render 'zuora_connect/static/error_unhandled', :locals => {:exception => ex, :skip_exception => true}, status: 500, layout: false}
end
return
end
def persist_connect_app_session
if @appinstance.present?
if defined?(Redis.current)
@appinstance.cache_app_instance
else
session.merge!(@appinstance.save_data)
end
end
end
def check_connect_admin!(raise_error: false)
if !session["#{@appinstance.id}::admin"]
raise ZuoraConnect::Exceptions::AccessDenied.new("User is not an authorized admin for this application") if raise_error
respond_to do |format|
format.html {
render "zuora_connect/static/error_handled", :locals => {
:title => "Unauthorized",
:message => "User is not an authorized admin for this application"
}, status: 401, :layout => false
}
format.js {
render "zuora_connect/static/error_handled", :locals => {
:title => "Unauthorized",
:message => "User is not an authorized admin for this application"
}, status: 401, :layout => false
}
format.json { render json: {'errors' => ex.message}, status: 401 }
format.all { render json: ex.message, status: 401 }
end
return
end
end
def check_connect_admin
return session["#{@appinstance.id}::admin"]
end
def zuora_user
return @zuora_user
end
def hallway_integration?
return (request.headers['ZuoraCurrentEntity'].present? || cookies['ZuoraCurrentEntity'].present?)
end
private
def setup_instance_via_prod_mode
zuora_entity_id = request.headers['ZuoraCurrentEntity'] || cookies['ZuoraCurrentEntity']
if zuora_entity_id.present?
zuora_tenant_id = cookies['Zuora-Tenant-Id']
zuora_user_id = cookies['Zuora-User-Id']
zuora_host = request.headers["HTTP_X_FORWARDED_HOST"] || "apisandbox.zuora.com"
zuora_details = {'host' => zuora_host, 'user_id' => zuora_user_id, 'tenant_id' => zuora_tenant_id, 'entity_id' => zuora_entity_id}
auth_headers = {}
#Do we need to refresh session identity
if request.headers["Zuora-Auth-Token"].present?
zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", bearer_token: request.headers["Zuora-Auth-Token"], entity_id: zuora_entity_id, oauth_session_expires_at: Time.now + 5.minutes )
elsif cookies['ZSession'].present?
zuora_client = ZuoraAPI::Basic.new(url: "https://#{zuora_host}", session: cookies['ZSession'], entity_id: zuora_entity_id)
auth_headers.merge!({'Authorization' => "ZSession-a3N2w #{zuora_client.get_session(prefix: false, auth_type: :basic)}"})
else
render "zuora_connect/static/error_handled", :locals => {
:title => "Missing Authorization Token",
:message => "Zuora 'Zuora-Auth-Token' header and 'ZSession' cookie not present."
}, :layout => false
return
end
begin
zuora_instance_id = params[:sidebar_launch].to_s.to_bool ? nil : (params[:app_instance_id] || session["appInstance"])
#Identity blank or current entity different
different_zsession = session["ZSession"] != cookies['ZSession']
missmatched_entity = session["ZuoraCurrentEntity"] != zuora_entity_id
missing_identity = session["ZuoraCurrentIdentity"].blank?
if (missing_identity || missmatched_entity || different_zsession)
zuora_details.merge!({'identity' => {'different_zsession' => different_zsession, 'missing_identity' => missing_identity, 'missmatched_entity' => missmatched_entity}})
identity, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("identity"))
if zuora_entity_id != identity['entityId']
if zuora_tenant_id.to_s == "10548"
session.clear
render "zuora_connect/static/error_handled", :locals => {
:title => "Security Testing",
:message => "Ya we know it you"
}, :layout => false
return
else
raise ZuoraConnect::Exceptions::Error.new("Header entity id does not match identity call entity id.")
end
end
##
# If the ZSession was refreshed, but it's still the same user and they aren't launching from the side bar,
# we don't need to continue
is_same_user = identity.slice("entityId", "tenantId", "userId", "userProfileId") == (session["ZuoraCurrentIdentity"] || {}).slice("entityId", "tenantId", "userId", "userProfileId")
zuora_details["identity"]["entityId"] = identity['entityId']
session["ZuoraCurrentIdentity"] = identity
session["ZuoraCurrentEntity"] = identity['entityId']
session["ZSession"] = cookies['ZSession']
unless is_same_user && !params[:sidebar_launch].to_s.to_bool
zuora_instance_id = nil
ZuoraConnect.logger.debug("UI Authorization", zuora: zuora_details)
client_describe, response = zuora_client.rest_call(
url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''),
session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic,
headers: auth_headers
)
session["ZuoraCurrentUserInfo"] = client_describe
end
end
#Find matching app instances.
if zuora_instance_id.present?
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.to_i).pluck(:id, :name)
else
#if app_instance_ids is present then permissions still controlled by connect
if params[:app_instance_ids].present?
navbar, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("navigation"))
urls = navbar['menus'].map {|x| x['url']}
app_env = ENV["DEIS_APP"] || "xyz123"
url = urls.compact.select {|url| File.basename(url).start_with?(app_env + '?')}.first
if url.blank?
if navbar['menus'].map {|x| x['label']}.include?('Link Connect Account')
render "zuora_connect/static/error_handled", :locals => {
:title => "Link Account",
:message => "Link Connect account to gain access to application."
}, :layout => false
return
end
raise ZuoraConnect::Exceptions::APIError.new(message: "#{app_env} navbar url was blank", response: response)
else
query_params = CGI.parse(URI.parse(url).query)
app_instance_ids = query_params["app_instance_ids"][0]
if app_instance_ids.present?
begin
task_ids = JSON.parse(Base64.urlsafe_decode64(app_instance_ids))
appinstances = ZuoraConnect::AppInstance.where(:id => task_ids).pluck(:id, :name)
rescue => ex
raise ZuoraConnect::Exceptions::APIError.new(message: "Failure in parsing the navbar urls.", response: response)
end
end
end
end
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)
end
zuora_user_id = cookies['Zuora-User-Id'] || session["ZuoraCurrentIdentity"]['userId']
#One deployed instance
if appinstances.size == 1
ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
@appinstance = ZuoraConnect::AppInstance.find(appinstances.to_h.keys.first)
#Add user/update
begin
@zuora_user = ZuoraConnect::ZuoraUser.where(:zuora_user_id => zuora_user_id).first
rescue ActiveRecord::StatementInvalid => ex
if ex.message.include?("PG::UndefinedTable") && ex.message.include?("zuora_users")
@appinstance.apartment_switch(nil,true)
retry
else
raise
end
end
if @zuora_user.present?
ZuoraConnect.logger.debug("Current zuora user #{zuora_user_id}")
if @zuora_user.updated_at < Time.now - 1.day
@zuora_user.zuora_identity_response[zuora_entity_id] = session["ZuoraCurrentIdentity"]
@zuora_user.save!
end
else
ZuoraConnect.logger.debug("New zuora user object for #{zuora_user_id}")
@zuora_user = ZuoraConnect::ZuoraUser.create!(:zuora_user_id => zuora_user_id, :zuora_identity_response => {zuora_entity_id => session["ZuoraCurrentIdentity"]})
end
@zuora_user.session = session
session["#{@appinstance.id}::user::localUserId"] = @zuora_user.id
session["#{@appinstance.id}::user::email"] = session['ZuoraCurrentIdentity']["username"]
session["#{@appinstance.id}::user::timezone"] = session['ZuoraCurrentIdentity']["timeZone"]
session["#{@appinstance.id}::user::locale"] = session['ZuoraCurrentIdentity']["language"]
session["appInstance"] = @appinstance.id
#We have multiple, user must pick
elsif appinstances.size > 1
ZuoraConnect.logger.debug("User must select instance. #{@names}")
render "zuora_connect/static/launch", :locals => {:names => appinstances.to_h}, :layout => false
return
#We have no deployed instance for this tenant
else
#Ensure user can access oauth creation API
if !session["ZuoraCurrentUserInfo"]['permissions'].include?("permission.userManagement")
Thread.current[:appinstance] = nil
session["appInstance"] = nil
render "zuora_connect/static/error_handled", :locals => {
:title => "Application can only complete its initial setup via platform administrator",
:message => "Please contact admin who has user managment permissions in tenant and have them click and finish setup."
}, :layout => false
return
end
Apartment::Tenant.switch!("public")
ActiveRecord::Base.transaction do
ActiveRecord::Base.connection.execute('LOCK public.zuora_users IN ACCESS EXCLUSIVE MODE')
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)
if appinstances.size > 0
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
return
end
next_id = (ZuoraConnect::AppInstance.all.where('id > 24999999').order(id: :desc).limit(1).pluck(:id).first || 24999999) + 1
user = (ENV['DEIS_APP'] || "Application").split('-').map(&:capitalize).join(' ')
body = {
'userId' => zuora_user_id,
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
'customAuthorities' => [],
'additionalInformation' => {
'description' => "This user is for #{user} application.",
'name' => "#{user} API User #{next_id}"
}
}
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: auth_headers
)
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
if session["ZuoraCurrentUserInfo"].blank?
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
else
client_describe = session["ZuoraCurrentUserInfo"]
end
available_entities = client_describe["accessibleEntities"].select {|entity| entity['id'] == zuora_entity_id}
task_data = {
"id": next_id,
"name": client_describe["tenantName"],
"mode": "Collections",
"status": "Running",
ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION => {
"tenant_type": "Zuora",
"username": session["ZuoraCurrentIdentity"]["username"],
"url": new_zuora_client.url,
"status": "Active",
"oauth_client_id": oauth_response['clientId'],
"oauth_secret": oauth_response['clientSecret'],
"authentication_type": "OAUTH",
"entities": available_entities.map {|e| e.merge({'displayName' => client_describe["tenantName"]})}
},
"tenant_ids": available_entities.map{|e| e['entityId']}.uniq,
}
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]}
@appinstance = ZuoraConnect::AppInstance.new(mapped_values)
retry_count = 0
begin
@appinstance.save(:validate => false)
rescue ActiveRecord::RecordNotUnique => ex
if (retry_count += 1) < 3
@appinstance.assign_attributes({:api_token => rand(36**64).to_s(36), :token => rand(36**64).to_s(36)})
retry
else
Thread.current[:appinstance] = nil
session["appInstance"] = nil
render "zuora_connect/static/error_handled", :locals => {
:title => "Application could not create unique tokens.",
:message => "Please contact support or retry launching application."
}, :layout => false
return
end
end
end
Apartment::Tenant.switch!("public")
begin
Apartment::Tenant.create(@appinstance.id.to_s)
rescue Apartment::TenantExists => ex
ZuoraConnect.logger.debug("Tenant Already Exists")
end
@appinstance.refresh
session["appInstance"] = @appinstance.id
end
rescue ZuoraAPI::Exceptions::ZuoraAPIAuthenticationTypeError => ex
output_xml, input_xml, response = zuora_client.soap_call(errors: [], z_session: false) do |xml|
xml['api'].getUserInfo
end
final_error = output_xml.xpath('//fns:FaultCode', 'fns' =>'http://fault.api.zuora.com/').text
session.clear
if final_error.blank?
ZuoraConnect.logger.warn("UI Authorization Error", ex, zuora: zuora_details.merge({:error => response.body}))
elsif final_error != "INVALID_SESSION"
ZuoraConnect.logger.warn("UI Authorization Error", ex, zuora: zuora_details.merge({:error => final_error}))
else
ZuoraConnect.logger.info("UI Authorization Error", ex, zuora: zuora_details.merge({:error => final_error}))
end
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
return
rescue ZuoraAPI::Exceptions::ZuoraAPIError, Exception => ex
if ex.message.include?("Referenced User resource(s) not found") && ex.class == ZuoraAPI::Exceptions::ZuoraAPIError
locals = {title: "Provisioning Error", message: "New tenats need to be provisioned by API Gateway('#{ex.message}'). Please contact support."}
render "zuora_connect/static/error_handled", locals: locals, status: 400, layout: false
else
session.clear
if defined?(ex.response) && ex.response.present? && defined?(ex.response.body)
zuora_details.merge!({:error => ex.response.body})
end
ZuoraConnect.logger.error("UI Authorization Error", ex, zuora: zuora_details)
render "zuora_connect/static/error_unhandled", locals: {exception: ex, skip_exception: true}, layout: false, status: 500
end
return
end
elsif request["data"].present? && (request["connectInstanceId"].present? || /^([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))
session.clear
values = JSON.parse(ZuoraConnect::AppInstance.decrypt_response(Base64.urlsafe_decode64(request["data"])))
values.fetch("param_data", {}).each do |k ,v|
params[k] = v
end
session["#{values["appInstance"]}::destroy"] = values["destroy"]
session["appInstance"] = values["appInstance"]
if values["current_user"]
session["#{values["appInstance"]}::admin"] = values["current_user"]["admin"] ? values["current_user"]["admin"] : false
session["#{values["appInstance"]}::user::timezone"] = values["current_user"]["timezone"]
session["#{values["appInstance"]}::user::locale"] = values["current_user"]["locale"]
session["#{values["appInstance"]}::user::email"] = values["current_user"]["email"]
end
@appinstance = ZuoraConnect::AppInstance.find_by(:id => values["appInstance"].to_i)
if @appinstance.blank?
Apartment::Tenant.switch!("public")
begin
Apartment::Tenant.create(values["appInstance"].to_s)
rescue Apartment::TenantExists => ex
ZuoraConnect.logger.debug("Tenant Already Exists")
end
mapped_values = {:api_token => values['api_token'], :token => values['api_token'], :access_token => values["access_token"], :refresh_token => values["refresh_token"], :oauth_expires_at => values["expires"]}
@appinstance = ZuoraConnect::AppInstance.new(mapped_values.merge({:id => values["appInstance"].to_i}))
@appinstance.save(:validate => false)
else
mapped_values = {:access_token => values["access_token"], :refresh_token => values["refresh_token"], :oauth_expires_at => values["expires"]}
@appinstance.assign_attributes(mapped_values)
if @appinstance.access_token_changed? && @appinstance.refresh_token_changed?
@appinstance.save(:validate => false)
else
raise ZuoraConnect::Exceptions::AccessDenied.new("Authorization mismatch. Possible tampering with session.")
end
end
else
if session["appInstance"].present?
@appinstance = ZuoraConnect::AppInstance.find_by(:id => session["appInstance"])
else
raise ZuoraConnect::Exceptions::AccessDenied.new("No application state or session found.")
end
end
end
def setup_instance_via_dev_mode
session["appInstance"] = ZuoraConnect.configuration.dev_mode_appinstance
user = ZuoraConnect.configuration.dev_mode_user
key = ZuoraConnect.configuration.dev_mode_pass
values = {:user => user , :key => key, :appinstance => session["appInstance"]}
@appinstance = ZuoraConnect::AppInstance.find_by(:id => values[:appinstance].to_i)
if @appinstance.blank?
Apartment::Tenant.switch!("public")
begin
Apartment::Tenant.create(values[:appinstance].to_s)
rescue Apartment::TenantExists => ex
Apartment::Tenant.drop(values[:appinstance].to_s)
retry
end
@appinstance = ZuoraConnect::AppInstance.new(:id => values[:appinstance].to_i, :access_token => values[:user], :refresh_token => values[:key], :token => "#{values[:key]}#{values[:key]}", :api_token => "#{values[:key]}#{values[:key]}")
@appinstance.save(:validate => false)
end
if @appinstance.access_token.blank? || @appinstance.refresh_token.blank? || @appinstance.token.blank? || @appinstance.api_token.blank?
@appinstance.update_attributes!(:access_token => values["user"], :refresh_token => values["key"], :token => "#{values[:key]}#{values[:key]}", :api_token => "#{values[:key]}#{values[:key]}")
end
session["#{@appinstance.id}::admin"] = ZuoraConnect.configuration.dev_mode_admin
end
end
end
end