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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +44 -0
  4. data/lib/generators/paypal/sdk/USAGE +3 -0
  5. data/lib/generators/paypal/sdk/install_generator.rb +17 -0
  6. data/lib/generators/paypal/sdk/templates/paypal.rb +2 -0
  7. data/lib/generators/paypal/sdk/templates/paypal.yml +31 -0
  8. data/lib/paypal-sdk-core.rb +38 -0
  9. data/lib/paypal-sdk/core/api.rb +20 -0
  10. data/lib/paypal-sdk/core/api/base.rb +162 -0
  11. data/lib/paypal-sdk/core/api/data_types/array_with_block.rb +44 -0
  12. data/lib/paypal-sdk/core/api/data_types/base.rb +224 -0
  13. data/lib/paypal-sdk/core/api/data_types/enum.rb +26 -0
  14. data/lib/paypal-sdk/core/api/data_types/simple_types.rb +52 -0
  15. data/lib/paypal-sdk/core/api/ipn.rb +66 -0
  16. data/lib/paypal-sdk/core/api/rest.rb +163 -0
  17. data/lib/paypal-sdk/core/authentication.rb +66 -0
  18. data/lib/paypal-sdk/core/config.rb +249 -0
  19. data/lib/paypal-sdk/core/credential.rb +16 -0
  20. data/lib/paypal-sdk/core/credential/base.rb +27 -0
  21. data/lib/paypal-sdk/core/credential/certificate.rb +32 -0
  22. data/lib/paypal-sdk/core/credential/signature.rb +22 -0
  23. data/lib/paypal-sdk/core/credential/third_party/subject.rb +25 -0
  24. data/lib/paypal-sdk/core/credential/third_party/token.rb +39 -0
  25. data/lib/paypal-sdk/core/exceptions.rb +96 -0
  26. data/lib/paypal-sdk/core/logging.rb +45 -0
  27. data/lib/paypal-sdk/core/openid_connect.rb +122 -0
  28. data/lib/paypal-sdk/core/openid_connect/api.rb +49 -0
  29. data/lib/paypal-sdk/core/openid_connect/data_types.rb +73 -0
  30. data/lib/paypal-sdk/core/openid_connect/get_api.rb +28 -0
  31. data/lib/paypal-sdk/core/openid_connect/request_data_type.rb +52 -0
  32. data/lib/paypal-sdk/core/openid_connect/set_api.rb +36 -0
  33. data/lib/paypal-sdk/core/util.rb +11 -0
  34. data/lib/paypal-sdk/core/util/http_helper.rb +159 -0
  35. data/lib/paypal-sdk/core/util/oauth_signature.rb +64 -0
  36. data/lib/paypal-sdk/core/util/ordered_hash.rb +165 -0
  37. data/lib/paypal-sdk/rest/data_types.rb +1 -0
  38. data/lib/paypal-sdk/rest/version.rb +1 -1
  39. data/spec/config/paypal.yml +27 -0
  40. data/spec/config/sample_data.yml +3 -0
  41. data/spec/core/api/data_type_spec.rb +189 -0
  42. data/spec/core/api/rest_spec.rb +147 -0
  43. data/spec/core/config_spec.rb +192 -0
  44. data/spec/core/logging_spec.rb +28 -0
  45. data/spec/core/openid_connect_spec.rb +144 -0
  46. data/spec/log/http.log +71 -32
  47. data/spec/log/rest_http.log +133 -0
  48. data/spec/spec_helper.rb +7 -0
  49. data/spec/support/sample_data.rb +5 -0
  50. 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