paypal-sdk-rest 0.10.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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