# encoding: UTF-8 # # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved. # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. require 'uri' require_relative 'core/logging' require_relative 'rest/rest' module GoodData class << self DEFAULT_SSO_OPTIONS = { :url => '/gdc/app/account/bootstrap', :valid => 24 * 60 * 60 } # Returns the active GoodData connection earlier initialized via GoodData.connect call # # @see GoodData.connect def connection # TODO: Remove this after successful rest-factory transition Rest::Client.connection # || fail('Please authenticate with GoodData.connect first') end alias_method :client, :connection # Connect to the GoodData API # # @param options # @param second_options # @param third_options # def connect(options = nil, second_options = nil, third_options = {}) Rest::Client.connect(options, second_options, third_options) end # Disconnect (logout) if logged in def disconnect Rest::Client.disconnect end def with_connection(options = nil, second_options = nil, third_options = {}, &block) client = connect(options, second_options, third_options) block.call(client) ensure disconnect end # Generates SSO URL # # This SSO implementation is custom implementation provided by GoodData # that allows your application to sign in an existing GoodData user. # The authentication is done not by username and password but by generating a session # specific token using pair of PGP keys. # # @see https://developer.gooddata.com/article/single-sign-on # # @param [String] login Email address used for logging into gooddata # @param [String] provider Name of SSO provider # @param [Hash] opts Additional options # @option opts [Fixnum] :validity Validity in seconds from 'now' # @return [String] URL which can be used for SSO logging in def sso_url(login, provider, url, opts = DEFAULT_SSO_OPTIONS) opts = DEFAULT_SSO_OPTIONS.merge(opts) ts = DateTime.now.strftime('%s').to_i + opts[:valid] obj = { 'email' => login, 'validity' => ts } json_data = JSON.pretty_generate(obj) + "\n" file_json = Tempfile.new('gooddata-sso-json') file_json.write(json_data) file_json.rewind file_signed = Tempfile.new('gooddata-sso-signed') cmd = "gpg --yes --no-tty --armor -u #{login} --output #{file_signed.path} --sign #{file_json.path}" res = system(cmd) fail 'Unable to sign json' unless res file_signed.rewind file_final = Tempfile.new('gooddata-sso-final') recipient = url == GoodData::Rest::Connection::DEFAULT_URL ? 'secure@gooddata.com' : 'test@gooddata.com' cmd = "gpg --yes --no-tty --trust-model always --armor --output #{file_final.path} --encrypt --recipient #{recipient} #{file_signed.path}" res = system(cmd) fail 'Unable to encrypt json' unless res file_final.rewind final = file_final.read params = { targetUrl: opts[:url], ssoProvider: provider, encryptedClaims: final } [url + '/gdc/account/customerlogin', params] end # Connect to GoodData using SSO # # This SSO implementation is custom implementation provided by GoodData # that allows your application to sign in an existing GoodData user. # The authentication is done not by username and password but by generating a session # specific token using pair of PGP keys. # # @see https://developer.gooddata.com/article/single-sign-on # # @param [String] login Email address used for logging into gooddata # @param [String] provider Name of SSO provider # @return [GoodData::Rest::Client] Instance of REST client def connect_sso(login, provider, url = GoodData::Rest::Connection::DEFAULT_URL, opts = {}) url, params = sso_url(login, provider, url) RestClient::Request.execute(opts.merge(method: :post, url: url, payload: params)) do |response, _request, _result| return Rest::Client.connect_sso( opts.merge( headers: { x_gdc_authsst: response.cookies['GDCAuthSST'], x_gdc_authtt: response.cookies['GDCAuthTT'] } ) ) end end end end