paypal-sdk-rest 0.10.0 → 1.0.0
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/Gemfile +1 -1
- data/README.md +44 -0
- data/lib/generators/paypal/sdk/USAGE +3 -0
- data/lib/generators/paypal/sdk/install_generator.rb +17 -0
- data/lib/generators/paypal/sdk/templates/paypal.rb +2 -0
- data/lib/generators/paypal/sdk/templates/paypal.yml +31 -0
- data/lib/paypal-sdk-core.rb +38 -0
- data/lib/paypal-sdk/core/api.rb +20 -0
- data/lib/paypal-sdk/core/api/base.rb +162 -0
- data/lib/paypal-sdk/core/api/data_types/array_with_block.rb +44 -0
- data/lib/paypal-sdk/core/api/data_types/base.rb +224 -0
- data/lib/paypal-sdk/core/api/data_types/enum.rb +26 -0
- data/lib/paypal-sdk/core/api/data_types/simple_types.rb +52 -0
- data/lib/paypal-sdk/core/api/ipn.rb +66 -0
- data/lib/paypal-sdk/core/api/rest.rb +163 -0
- data/lib/paypal-sdk/core/authentication.rb +66 -0
- data/lib/paypal-sdk/core/config.rb +249 -0
- data/lib/paypal-sdk/core/credential.rb +16 -0
- data/lib/paypal-sdk/core/credential/base.rb +27 -0
- data/lib/paypal-sdk/core/credential/certificate.rb +32 -0
- data/lib/paypal-sdk/core/credential/signature.rb +22 -0
- data/lib/paypal-sdk/core/credential/third_party/subject.rb +25 -0
- data/lib/paypal-sdk/core/credential/third_party/token.rb +39 -0
- data/lib/paypal-sdk/core/exceptions.rb +96 -0
- data/lib/paypal-sdk/core/logging.rb +45 -0
- data/lib/paypal-sdk/core/openid_connect.rb +122 -0
- data/lib/paypal-sdk/core/openid_connect/api.rb +49 -0
- data/lib/paypal-sdk/core/openid_connect/data_types.rb +73 -0
- data/lib/paypal-sdk/core/openid_connect/get_api.rb +28 -0
- data/lib/paypal-sdk/core/openid_connect/request_data_type.rb +52 -0
- data/lib/paypal-sdk/core/openid_connect/set_api.rb +36 -0
- data/lib/paypal-sdk/core/util.rb +11 -0
- data/lib/paypal-sdk/core/util/http_helper.rb +159 -0
- data/lib/paypal-sdk/core/util/oauth_signature.rb +64 -0
- data/lib/paypal-sdk/core/util/ordered_hash.rb +165 -0
- data/lib/paypal-sdk/rest/data_types.rb +1 -0
- data/lib/paypal-sdk/rest/version.rb +1 -1
- data/spec/config/paypal.yml +27 -0
- data/spec/config/sample_data.yml +3 -0
- data/spec/core/api/data_type_spec.rb +189 -0
- data/spec/core/api/rest_spec.rb +147 -0
- data/spec/core/config_spec.rb +192 -0
- data/spec/core/logging_spec.rb +28 -0
- data/spec/core/openid_connect_spec.rb +144 -0
- data/spec/log/http.log +71 -32
- data/spec/log/rest_http.log +133 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/sample_data.rb +5 -0
- metadata +82 -5
@@ -0,0 +1,16 @@
|
|
1
|
+
module PayPal
|
2
|
+
module SDK
|
3
|
+
module Core
|
4
|
+
module Credential
|
5
|
+
autoload :Base, "paypal-sdk/core/credential/base"
|
6
|
+
autoload :Certificate, "paypal-sdk/core/credential/certificate"
|
7
|
+
autoload :Signature, "paypal-sdk/core/credential/signature"
|
8
|
+
|
9
|
+
module ThirdParty
|
10
|
+
autoload :Token, "paypal-sdk/core/credential/third_party/token"
|
11
|
+
autoload :Subject, "paypal-sdk/core/credential/third_party/subject"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PayPal::SDK::Core
|
2
|
+
module Credential
|
3
|
+
|
4
|
+
# Base credential Class for authentication
|
5
|
+
class Base
|
6
|
+
attr_accessor :username, :password, :app_id, :device_ipaddress, :sandbox_email_address
|
7
|
+
|
8
|
+
# Initialize authentication configurations
|
9
|
+
# === Arguments
|
10
|
+
# * <tt>config</tt> -- Configuration object
|
11
|
+
def initialize(config)
|
12
|
+
self.username = config.username
|
13
|
+
self.password = config.password
|
14
|
+
self.app_id = config.app_id
|
15
|
+
self.device_ipaddress = config.device_ipaddress
|
16
|
+
self.sandbox_email_address = config.sandbox_email_address
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return credential properties
|
20
|
+
def properties
|
21
|
+
{ :username => username, :password => password, :app_id => app_id,
|
22
|
+
:device_ipaddress => device_ipaddress, :sandbox_email_address => sandbox_email_address }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PayPal::SDK::Core
|
2
|
+
module Credential
|
3
|
+
|
4
|
+
# Certificate class for SSL Certificate authentication
|
5
|
+
class Certificate < Base
|
6
|
+
|
7
|
+
attr_reader :cert_path
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
super
|
11
|
+
@cert_path = config.cert_path
|
12
|
+
end
|
13
|
+
|
14
|
+
# Return SSL certificate
|
15
|
+
def cert
|
16
|
+
@cert ||= OpenSSL::X509::Certificate.new(cert_content)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return SSL certificate key
|
20
|
+
def key
|
21
|
+
@key = OpenSSL::PKey::RSA.new(cert_content)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
# Return certificate content from the configured file.
|
26
|
+
def cert_content
|
27
|
+
@cert_content ||= File.read(cert_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module PayPal::SDK::Core
|
2
|
+
module Credential
|
3
|
+
class Signature < Base
|
4
|
+
|
5
|
+
attr_accessor :signature
|
6
|
+
|
7
|
+
# Initialize configuration
|
8
|
+
# === Argument
|
9
|
+
# * <tt>config</tt> -- Configuration object
|
10
|
+
def initialize(config)
|
11
|
+
super
|
12
|
+
self.signature = config.signature
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return properties for authentication
|
16
|
+
def properties
|
17
|
+
super.merge({ :signature => signature })
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module PayPal::SDK::Core
|
2
|
+
module Credential
|
3
|
+
module ThirdParty
|
4
|
+
class Subject
|
5
|
+
|
6
|
+
attr_accessor :subject, :credential
|
7
|
+
|
8
|
+
# Initialize configuration
|
9
|
+
# === Arguments
|
10
|
+
# * <tt>credential</tt> -- Credential object
|
11
|
+
# * <tt>config</tt> -- Configuration object
|
12
|
+
def initialize(credential, config)
|
13
|
+
@credential = credential
|
14
|
+
@subject = config.subject
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return properties for authentication.
|
18
|
+
def properties
|
19
|
+
credential.properties.merge( :subject => subject )
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module PayPal::SDK::Core
|
2
|
+
module Credential
|
3
|
+
module ThirdParty
|
4
|
+
class Token
|
5
|
+
|
6
|
+
attr_accessor :token, :token_secret, :credential, :url
|
7
|
+
|
8
|
+
# Initialize Token credentials
|
9
|
+
# === Arguments
|
10
|
+
# * <tt>credential</tt> -- Credential Object
|
11
|
+
# * <tt>config</tt> -- Configuration object
|
12
|
+
# * <tt>url</tt> -- Request url
|
13
|
+
def initialize(credential, config, url)
|
14
|
+
@credential = credential
|
15
|
+
@token = config.token
|
16
|
+
@token_secret = config.token_secret
|
17
|
+
@url = url
|
18
|
+
end
|
19
|
+
|
20
|
+
RemoveProperties = [ :username, :password, :signature ]
|
21
|
+
|
22
|
+
# Return credential properties for authentication.
|
23
|
+
def properties
|
24
|
+
credential_properties = credential.properties
|
25
|
+
credential_properties.delete_if{|k,v| RemoveProperties.include? k }
|
26
|
+
credential_properties.merge( :authorization => oauth_authentication )
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
# Return OAuth authentication string.
|
31
|
+
def oauth_authentication
|
32
|
+
Util::OauthSignature.new(credential.username, credential.password, token, token_secret, url).
|
33
|
+
authorization_string
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module PayPal::SDK::Core
|
5
|
+
module Exceptions
|
6
|
+
class ConnectionError < StandardError # :nodoc:
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def initialize(response, message = nil)
|
10
|
+
@response = response
|
11
|
+
@message = message
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
begin
|
16
|
+
response_body = JSON.parse(response.body)
|
17
|
+
debug_id = response_body["debug_id"]
|
18
|
+
rescue
|
19
|
+
end
|
20
|
+
message = "Failed."
|
21
|
+
message << " Response code = #{response.code}." if response.respond_to?(:code)
|
22
|
+
message << " Response message = #{response.message}." if response.respond_to?(:message)
|
23
|
+
message << " Response debug ID = #{debug_id}." if debug_id
|
24
|
+
message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Raised when a Timeout::Error occurs.
|
29
|
+
class TimeoutError < ConnectionError
|
30
|
+
def initialize(message)
|
31
|
+
@message = message
|
32
|
+
end
|
33
|
+
def to_s; @message ;end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Raised when a OpenSSL::SSL::SSLError occurs.
|
37
|
+
class SSLError < ConnectionError
|
38
|
+
def initialize(message)
|
39
|
+
@message = message
|
40
|
+
end
|
41
|
+
def to_s; @message ;end
|
42
|
+
end
|
43
|
+
|
44
|
+
# 3xx Redirection
|
45
|
+
class Redirection < ConnectionError # :nodoc:
|
46
|
+
def to_s
|
47
|
+
response['Location'] ? "#{super} => #{response['Location']}" : super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class MissingParam < ArgumentError # :nodoc:
|
52
|
+
end
|
53
|
+
|
54
|
+
class MissingConfig < StandardError # :nodoc:
|
55
|
+
end
|
56
|
+
|
57
|
+
# 4xx Client Error
|
58
|
+
class ClientError < ConnectionError # :nodoc:
|
59
|
+
end
|
60
|
+
|
61
|
+
# 400 Bad Request
|
62
|
+
class BadRequest < ClientError # :nodoc:
|
63
|
+
end
|
64
|
+
|
65
|
+
# 401 Unauthorized
|
66
|
+
class UnauthorizedAccess < ClientError # :nodoc:
|
67
|
+
end
|
68
|
+
|
69
|
+
# 403 Forbidden
|
70
|
+
class ForbiddenAccess < ClientError # :nodoc:
|
71
|
+
end
|
72
|
+
|
73
|
+
# 404 Not Found
|
74
|
+
class ResourceNotFound < ClientError # :nodoc:
|
75
|
+
end
|
76
|
+
|
77
|
+
# 409 Conflict
|
78
|
+
class ResourceConflict < ClientError # :nodoc:
|
79
|
+
end
|
80
|
+
|
81
|
+
# 410 Gone
|
82
|
+
class ResourceGone < ClientError # :nodoc:
|
83
|
+
end
|
84
|
+
|
85
|
+
# 5xx Server Error
|
86
|
+
class ServerError < ConnectionError # :nodoc:
|
87
|
+
end
|
88
|
+
|
89
|
+
# 405 Method Not Allowed
|
90
|
+
class MethodNotAllowed < ClientError # :nodoc:
|
91
|
+
def allowed_methods
|
92
|
+
@response['Allow'].split(',').map { |verb| verb.strip.downcase.to_sym }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module PayPal::SDK::Core
|
4
|
+
# Include Logging module to provide logger functionality.
|
5
|
+
# == Configure logger
|
6
|
+
# Logging.logger = Logger.new(STDERR)
|
7
|
+
#
|
8
|
+
# == Example
|
9
|
+
# include Logger
|
10
|
+
# logger.info "Debug message"
|
11
|
+
module Logging
|
12
|
+
|
13
|
+
# Get logger object
|
14
|
+
def logger
|
15
|
+
@logger ||= Logging.logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def log_event(message, &block)
|
19
|
+
start_time = Time.now
|
20
|
+
block.call
|
21
|
+
ensure
|
22
|
+
logger.info sprintf("[%.3fs] %s", Time.now - start_time, message)
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
|
27
|
+
# Get or Create configured logger based on the default environment configuration
|
28
|
+
def logger
|
29
|
+
@logger ||= Logger.new(STDERR)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set logger directly and clear the loggers cache.
|
33
|
+
# === Attributes
|
34
|
+
# * <tt>logger</tt> -- Logger object
|
35
|
+
# === Example
|
36
|
+
# Logging.logger = Logger.new(STDERR)
|
37
|
+
def logger=(logger)
|
38
|
+
@logger = logger
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
|
2
|
+
module PayPal::SDK
|
3
|
+
module Core
|
4
|
+
module OpenIDConnect
|
5
|
+
autoload :API, "paypal-sdk/core/openid_connect/api"
|
6
|
+
autoload :SetAPI, "paypal-sdk/core/openid_connect/set_api"
|
7
|
+
autoload :GetAPI, "paypal-sdk/core/openid_connect/get_api"
|
8
|
+
autoload :RequestDataType, "paypal-sdk/core/openid_connect/request_data_type"
|
9
|
+
autoload :DataTypes, "paypal-sdk/core/openid_connect/data_types"
|
10
|
+
|
11
|
+
include DataTypes
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def api
|
15
|
+
RequestDataType.api
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_config(*args)
|
19
|
+
RequestDataType.set_config(*args)
|
20
|
+
end
|
21
|
+
alias_method :config=, :set_config
|
22
|
+
|
23
|
+
AUTHORIZATION_URL = "paypal.com/webapps/auth/protocol/openidconnect/v1/authorize"
|
24
|
+
ENDSESSION_URL = "paypal.com/webapps/auth/protocol/openidconnect/v1/endsession"
|
25
|
+
DEFAULT_SCOPE = "openid"
|
26
|
+
|
27
|
+
def authorize_url(params = {})
|
28
|
+
uri = URI(url_for_mode(AUTHORIZATION_URL))
|
29
|
+
uri.query = api.encode_www_form({
|
30
|
+
:response_type => "code",
|
31
|
+
:scope => DEFAULT_SCOPE,
|
32
|
+
:client_id => RequestDataType.client_id,
|
33
|
+
:redirect_uri => api.config.openid_redirect_uri
|
34
|
+
}.merge(params))
|
35
|
+
uri.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def logout_url(params = {})
|
39
|
+
uri = URI(url_for_mode(ENDSESSION_URL))
|
40
|
+
uri.query = api.encode_www_form({
|
41
|
+
:logout => "true",
|
42
|
+
:redirect_uri => api.config.openid_redirect_uri
|
43
|
+
}.merge(params))
|
44
|
+
uri.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def url_for_mode(url)
|
50
|
+
"https://www.#{"sandbox." if api.api_mode == :sandbox}#{url}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module DataTypes
|
55
|
+
class Tokeninfo < Base
|
56
|
+
include RequestDataType
|
57
|
+
PATH = "v1/identity/openidconnect/tokenservice"
|
58
|
+
|
59
|
+
class << self
|
60
|
+
def create_from_authorization_code(options, http_header = {})
|
61
|
+
options = { :code => options } if options.is_a? String
|
62
|
+
options = options.merge( :grant_type => "authorization_code" )
|
63
|
+
Tokeninfo.new(api.post(PATH, with_credentials(options), http_header))
|
64
|
+
end
|
65
|
+
alias_method :create, :create_from_authorization_code
|
66
|
+
|
67
|
+
def create_from_refresh_token(options, http_header = {})
|
68
|
+
options = { :refresh_token => options } if options.is_a? String
|
69
|
+
options = options.merge( :grant_type => "refresh_token" )
|
70
|
+
Tokeninfo.new(api.post(PATH, with_credentials(options), http_header))
|
71
|
+
end
|
72
|
+
alias_method :refresh, :create_from_refresh_token
|
73
|
+
|
74
|
+
def with_credentials(options = {})
|
75
|
+
options = options.dup
|
76
|
+
[ :client_id, :client_secret ].each do |key|
|
77
|
+
options[key] = self.send(key) unless options[key] or options[key.to_s]
|
78
|
+
end
|
79
|
+
options
|
80
|
+
end
|
81
|
+
|
82
|
+
def authorize_url(options = {})
|
83
|
+
OpenIDConnect.authorize_url(options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def refresh(options = {})
|
88
|
+
tokeninfo = self.class.refresh({
|
89
|
+
:refresh_token => self.refresh_token}.merge(options))
|
90
|
+
self.merge!(tokeninfo.to_hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
def userinfo(options = {})
|
94
|
+
Userinfo.get({ :access_token => self.access_token }.merge(options))
|
95
|
+
end
|
96
|
+
|
97
|
+
def logout_url(options = {})
|
98
|
+
OpenIDConnect.logout_url({ :id_token => self.id_token }.merge(options))
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
class Userinfo < Base
|
104
|
+
include RequestDataType
|
105
|
+
PATH = "v1/identity/openidconnect/userinfo"
|
106
|
+
|
107
|
+
class << self
|
108
|
+
def get_userinfo(options = {}, http_header = {})
|
109
|
+
options = { :access_token => options } if options.is_a? String
|
110
|
+
options = options.merge( :schema => "openid" ) unless options[:schema] or options["schema"]
|
111
|
+
Userinfo.new(api.post(PATH, options, http_header))
|
112
|
+
end
|
113
|
+
alias_method :get, :get_userinfo
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Alias for the Core::OpenIDConnect constant
|
121
|
+
OpenIDConnect = Core::OpenIDConnect
|
122
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
module PayPal::SDK
|
4
|
+
module Core
|
5
|
+
module OpenIDConnect
|
6
|
+
class API < Core::API::Base
|
7
|
+
|
8
|
+
DEFAULT_OPENID_ENDPOINT = {
|
9
|
+
:sandbox => "https://api.sandbox.paypal.com",
|
10
|
+
:live => "https://api.paypal.com" }
|
11
|
+
|
12
|
+
def initialize(environment = nil, options = {})
|
13
|
+
super("", environment, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def service_endpoint
|
17
|
+
self.config.openid_endpoint || DEFAULT_OPENID_ENDPOINT[self.api_mode] || DEFAULT_OPENID_ENDPOINT[:sandbox]
|
18
|
+
end
|
19
|
+
|
20
|
+
def format_request(payload)
|
21
|
+
payload[:uri].path = url_join(payload[:uri].path, payload[:action])
|
22
|
+
payload[:body] = encode_www_form(payload[:params]) if payload[:params]
|
23
|
+
payload[:header] = {"Content-Type" => "application/x-www-form-urlencoded" }.merge(payload[:header])
|
24
|
+
payload
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_response(payload)
|
28
|
+
payload[:data] =
|
29
|
+
if payload[:response].code >= "200" and payload[:response].code <= "299"
|
30
|
+
MultiJson.load(payload[:response].body)
|
31
|
+
elsif payload[:response].content_type == "application/json"
|
32
|
+
{ "error" => MultiJson.load(payload[:response].body) }
|
33
|
+
else
|
34
|
+
{ "error" => { "name" => payload[:response].code, "message" => payload[:response].message,
|
35
|
+
"developer_msg" => payload[:response] } }
|
36
|
+
end
|
37
|
+
payload
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def user_agent
|
42
|
+
@user_agent ||= "PayPalSDK/openid-connect-ruby #{VERSION} (#{sdk_library_details})"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|