sailpoint 0.0.3 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 948e79e40e1b960266502c666ca8db069ce15e302374c23012e95112a48b9b36
4
- data.tar.gz: 259569e390dd2d392be8e85d3d252ac531dd632dde2b39c4a49a2818eacc99f8
3
+ metadata.gz: 1220fcec1f06178a2d7a3ad3223c4f8a142c97a1c5c22a1a04cc7d0534fc2969
4
+ data.tar.gz: 0f4937b7f5a97782a0b2f0a86d7e09f621c196a33576c6149df973aa209ab9fa
5
5
  SHA512:
6
- metadata.gz: 37b621badd12c2c2028b28614403c105e2ab48557b8918d6ccddef7f19169fd339cfde06fc0eeb0b813da6bb7974cc64458817f07d92c8bae29a97d594401643
7
- data.tar.gz: d72001f42801aa0d29f10863619e5fe00e3d12852cee307068e9e3cb169b1935936cdd82843c359d370c7068c7c8a27badb6a280e728e6b18dbe990a6747843e
6
+ metadata.gz: c16e91fc84ec90643c25af0731eb20762488bd55a8e729e19a557fff8bf0c6186b3daa23773c04b9866a360c7eb0e0de91d480c4ff2029fb56f95e7dc7dd091e
7
+ data.tar.gz: 8f8e3c65082bf64acc9311621dce1cc1c734a032be70cd86cdcd3705605d4e28d467caa46c54cb7c1b06f23a0bd7fd068ea8350b0ced08156bc9a2a584e5db96
data/README.md CHANGED
@@ -46,24 +46,23 @@ If running from `irb` or wanting to call the IdentityIQ API from a ruby script u
46
46
  require 'sailpoint'
47
47
 
48
48
  # In order to make any API requests you need to specify the IdentityIQ API Host and set you API credentials
49
- Sailpoint.set_credentials('foo','bar')
50
- Sailpoint.set_host = 'https://example.com/';
51
- Sailpoint.get_user('sample_user')
49
+ Sailpoint.configure do |config|
50
+ config.username = 'api_username'
51
+ config.password = 'api_password'
52
+ config.host = 'https://example.com'
53
+ end
52
54
  ```
53
55
 
54
- ## Getting Started
55
-
56
56
  By default this will pull users from the REST API
57
57
  If you want to pull from the SCIM API there are a number of ways to do this as well
58
58
 
59
59
  ```ruby
60
60
  # First method
61
- Sailpoint.get_user('sample_user', interface: 'scim')
61
+ Sailpoint.get_user('sample_user')
62
62
 
63
63
  # Second method
64
64
  # Note: When reassigning the API interface future queries will hit the new API endpoint unless specified
65
- Sailpoint::Config.interface = 'scim'
66
- Sailpoint.get_user('sample_user')
65
+ Sailpoint::Rest.get_user('sample_user')
67
66
 
68
67
  # Third method (and my personal favorite to use without assigning the interface)
69
68
  Sailpoint::Scim.get_user('sample_user')
@@ -76,53 +75,47 @@ Lets first start by creating an initializer so you don't have to set the API con
76
75
  ```ruby
77
76
  # config/initializers/sailpoint.rb
78
77
  if defined?(Sailpoint)
79
- Sailpoint::Config.set_credentials('api_username', 'api_password')
80
- Sailpoint::Config.host = 'http://example.com/'
78
+ Sailpoint.configure do |config|
79
+ config.username = 'api_username'
80
+ config.password = 'api_password'
81
+ config.host = 'https://example.com'
82
+ end
81
83
  end
84
+ ```
82
85
 
83
86
  # If you're using encrypted credentials
87
+
88
+ ```ruby
84
89
  if defined?(Sailpoint)
85
- Sailpoint::Config.set_credentials(Rails.application.credentials[:sailpoint][:username], Rails.application.credentials[:sailpoint][:password])
86
- Sailpoint::Config.host = 'http://example.com/'
90
+ Sailpoint.configure do |config|
91
+ config.username = Rails.application.credentials[:sailpoint][:username]
92
+ config.password = Rails.application.credentials[:sailpoint][:password]
93
+ config.host = 'https://example.com'
94
+ end
87
95
  end
88
96
  ```
89
97
 
90
- Now in your controller, models, or wherever required you should be able to make an API request with the following command
98
+ Now in your controller or models you should be able to make an API request with the following command
91
99
 
92
100
  ```ruby
93
101
  Sailpoint.get_user('sample_user')
94
102
  ```
95
103
 
96
- # Misc
97
-
98
- ```ruby
99
- Sailpoint::Config.set_credentials('api_username', 'api_password'); Sailpoint::Config.host = 'http://example.com/';
100
- # Sailpoint::Config.interface = 'rest'
101
- # Sailpoint::Config.interface = 'scim'
102
- Sailpoint.get_user('username')
103
- ```
104
-
105
104
  ## General function calls
106
105
 
107
- Listed below are the majority of the functions used throughout the library and their intended purpose.
108
-
109
106
  * `Sailpoint.get_user(identity)` - Search the API resources for the specified user identity
110
- * `Sailpoint.set_credentials(username, password)` - Assign the credentials for accessing the IdentityIQ API
111
- * `Sailpoint.set_host(host)` - Assign the IdentityIQ API base URL
112
107
 
113
108
  ## Configuration
114
109
 
115
- * `Sailpoint::Config.auth_header` - Returns the BasicAuth Header for creating and API request
116
- * `Sailpoint::Config.credentials` - A hash containing the API credentials when setting API requests headers
117
- * `Sailpoint::Config.hashed_credentials` - A Base64 encoded string for the API request
118
- * `Sailpoint::Config.host` - Returns the API base host
119
- * `Sailpoint::Config.interface` - Returns the specified API interface (REST || SCIM)
120
- * `Sailpoint::Config.interface_path` - Returns the API path dependant on the interface
121
- * `Sailpoint::Config.password` - Returns the API password specified
122
- * `Sailpoint::Config.set_credentials(username, password)` - Used for assigning credentials for accessing the IndentityIQ API
123
- * `Sailpoint::Config.trimmed_host` - Returns the API base host with all trailing whitespace and slashs trimmed
124
- * `Sailpoint::Config.url` - Returns the full API URL based on the `host+interface`
125
- * `Sailpoint::Config.username` - If set, it returns the username credentials for API
110
+ * `Sailpoint.config.auth_header` - Returns the BasicAuth Header for creating and API request (if the username/password have been set)
111
+ * `Sailpoint.config.credentials` - A hash containing the API credentials when setting API requests headers
112
+ * `Sailpoint.config.hashed_credentials` - A Base64 encoded string for the API request
113
+ * `Sailpoint.config.host` - Returns the API base host
114
+ * `Sailpoint.config.interface` - Returns the specified API interface (REST || SCIM)
115
+ * `Sailpoint.config.interface_path` - Returns the API path dependant on the interface
116
+ * `Sailpoint.config.password` - Returns the API password specified
117
+ * `Sailpoint.config.url` - Returns the full API URL based on the `host+interface`
118
+ * `Sailpoint.config.username` - If set, it returns the username credentials for API
126
119
 
127
120
  ## Interface specific function calls
128
121
 
@@ -146,6 +139,11 @@ Listed below are the majority of the functions used throughout the library and t
146
139
  * `Sailpoint::Rest.permitted_roles(identity)` - Get a users roles within the Organization
147
140
  * `Sailpoint::Rest.ping` - Used to verify your credentials are valid and IdentityIQ reource is properly responding
148
141
 
142
+ ```shell
143
+ # Rebuilding the gem to test in a required IRB term
144
+ gem uninstall sailpoint; rm -rf sailpoint-0.1.0.gem; gem build; gem install sailpoint
145
+ ```
146
+
149
147
  ## API Documentation
150
148
 
151
149
  * [IdentityNow](https://api.identitynow.com/)
@@ -1,61 +1,71 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sailpoint/version'
2
- require 'sailpoint/config'
3
- require 'sailpoint/helpers' # To override defaults and adding global helper functions
4
+ require 'sailpoint/core_ext/blank'
5
+ require 'sailpoint/core_ext/escape_str'
4
6
  require 'sailpoint/rest'
5
7
  require 'sailpoint/scim'
6
8
 
7
- # Sailpoint Module to allow for easily accessing the Sailpoint API
8
9
  module Sailpoint
10
+ require 'sailpoint/helpers' # To override defaults and adding global helper functions
11
+ require 'sailpoint/configuration'
12
+
9
13
  # When generating a Standard Exception error
10
14
  class Error < StandardError; end
15
+ class << self
16
+ def config
17
+ @config ||= Configuration.new
18
+ end
11
19
 
12
- # If a valid username and URL have been supplied a lookup requests will be send to determine if the user exists in the specified interface
13
- # @param username [String] - the username that we are going to valid exists in the IdentityIQ listing
14
- # @return [Hash] - If a user is found, it will return all the that identities attributes
15
- def self.get_user(username, interface: nil)
16
- raise ArgumentError, 'An invalid user lookup was specified.' if username.to_s.blank?
17
- raise ArgumentError, 'Please specify a valid HOST/Interface before attemping a lookup.' unless valid_url?
18
- raise ArgumentError, 'Valid credentials are required before attempting an API request.' unless valid_credentials?
19
- raise ArgumentError, 'Invalid method type' unless valid_interface_type?(interface) || valid_interface_type?(Sailpoint::Config.interface)
20
-
21
- if interface.nil?
22
- Object.const_get("Sailpoint::#{Sailpoint::Config.interface.capitalize}").get_user(username)
23
- elsif valid_interface_type?(interface)
24
- Object.const_get("Sailpoint::#{interface.capitalize}").get_user(username)
20
+ # Used to memorize and create a Mutex to keep config in sync across running threads
21
+ #
22
+ # @return [Mutex]
23
+ def mutex
24
+ @mutex ||= Mutex.new
25
25
  end
26
- end
27
26
 
28
- # Assign the credentials for accessing the IdentityIQ API
29
- # @param username [String] - The Sailpoint username required for accessing the API
30
- # @param password [String] - The Sailpoint password required for accessing the API
31
- def self.set_credentials(username, password)
32
- Sailpoint::Config.set_credentials(username, password) unless username.nil? && password.nil?
33
- end
27
+ # If a valid username and URL have been supplied a lookup requests will be send to determine if the user exists in the specified interface
28
+ # @param username [String] - the username that we are going to valid exists in the IdentityIQ listing
29
+ # @return [Hash] - If a user is found, it will return all the that identities attributes
30
+ def get_user(username = '')
31
+ raise ArgumentError, 'An invalid user lookup was specified.' if username.blank?
32
+ raise ArgumentError, 'Please specify a valid HOST/Interface before attemping a lookup.' unless valid_url?
33
+ raise ArgumentError, 'Valid credentials are required before attempting an API request.' unless valid_credentials?
34
+ raise ArgumentError, 'Invalid interface type' unless valid_interface_type?(config.interface)
34
35
 
35
- # Assign the IdentityIQ API base URL
36
- # @param host [String] - The base URL in which the API calls will be built upon
37
- def self.set_host(host)
38
- Sailpoint::Config.host = host unless host.blank?
39
- end
36
+ if config.interface.blank?
37
+ Sailpoint::Scim.get_user(username)
38
+ else
39
+ Object.const_get("Sailpoint::#{config.interface&.capitalize}").get_user(username)
40
+ end
41
+ end
40
42
 
41
- # Used to verify if any credentails were supplied for the API request
42
- # @return [Boolean] if credentials were supplied or not
43
- def self.valid_credentials?
44
- return false if Sailpoint::Config.username.blank? && Sailpoint::Config.password.blank?
43
+ # Used to verify if any credentails were supplied for the API request
44
+ # @return [Boolean] if credentials were supplied or not
45
+ def valid_credentials?
46
+ return false if Sailpoint.config.username.blank? && Sailpoint.config.password.blank?
45
47
 
46
- !Sailpoint::Config.hashed_credentials.blank?
47
- end
48
+ !Sailpoint.config.hashed_credentials.blank?
49
+ end
48
50
 
49
- # Used to verify if the specifed interface type is valid for the Sailpoint API
50
- # @param interface [String] - A specified API interface endpoint, that can either be `Rest` or `Scim`
51
- # @return [Boolean] - Returns weither the specifed interface is a a valid type allowed by the API.
52
- def self.valid_interface_type?(interface)
53
- %w[rest scim].include?(interface)
54
- end
51
+ # Used to verify if the specifed interface type is valid for the Sailpoint API
52
+ # @param interface [String] - A specified API interface endpoint, that can either be `Rest` or `Scim`
53
+ # @return [Boolean] - Returns weither the specifed interface is a a valid type allowed by the API.
54
+ def valid_interface_type?(interface = nil)
55
+ return false if interface.blank?
56
+
57
+ Sailpoint::Configuration::ALLOWED_INTERFACES.include?(interface)
58
+ end
55
59
 
56
- # Used to verify if the URL string is blank or a URL was supplied
57
- # @return [Boolean] - if a url for the API endpoint was supplied or not
58
- def self.valid_url?
59
- !Sailpoint::Config.url.blank?
60
+ # Used to verify if the URL string is blank or a URL was supplied
61
+ # @return [Boolean] - if a url for the API endpoint was supplied or not
62
+ def valid_url?
63
+ !Sailpoint.config.url.blank?
64
+ end
65
+
66
+ def configure
67
+ self.config ||= config
68
+ yield(config)
69
+ end
60
70
  end
61
71
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'sailpoint/helpers'
5
+
6
+ # Used for setting you Sailpoint API configuration and credentials
7
+ module Sailpoint
8
+ # Used for setting API configuration before creating API Requests
9
+ # Configuration can include: <code>username, password, interface, host, url</code>
10
+ class Configuration
11
+ ALLOWED_INTERFACES = %w[rest scim].freeze
12
+
13
+ attr_accessor :password, :username
14
+
15
+ # Variables used for storing values for host= and interface=
16
+ attr_accessor :host_val, :interface_val
17
+
18
+ def initialize
19
+ reload_config
20
+ end
21
+
22
+ def host=(val = nil)
23
+ self.host_val = trim_host(val)
24
+ end
25
+
26
+ def host
27
+ host_val
28
+ end
29
+
30
+ def interface=(val = nil)
31
+ val = val&.to_s&.strip unless val.blank?
32
+ self.interface_val = begin
33
+ if val.blank? || !ALLOWED_INTERFACES.include?(val)
34
+ 'scim'
35
+ else
36
+ val
37
+ end
38
+ end
39
+ end
40
+
41
+ def interface
42
+ interface_val
43
+ end
44
+
45
+ # SailPoints auth requires a Base64 string of (username:password)
46
+ # This is how most BasicAuth authentication methods work
47
+ # @return [String] - It will either return an empty string or a Base64.encoded hash for the the API credentials (BasicAuth requires Base64)
48
+ def hashed_credentials
49
+ return '' if username.blank? && password.blank?
50
+
51
+ Base64.encode64("#{username}:#{password}").strip
52
+ end
53
+
54
+ # Used for fetching the API interface_path based on the API interface specification
55
+ # @return [String] - Returns the API's interface path, based on interface type
56
+ def interface_path
57
+ return 'scim' if interface.blank? || !ALLOWED_INTERFACES.include?(interface)
58
+
59
+ interface
60
+ end
61
+
62
+ # Used for fetching the requesting users entire URL (Host+Interface)
63
+ # @return [String] - Returns the entire requesting URL (based on host and interface type)
64
+ def url
65
+ return '' if host.blank? || interface.blank?
66
+
67
+ full_host(interface)
68
+ end
69
+
70
+ def full_host(interface = '')
71
+ (interface.blank? ? [host, 'identityiq', interface_path].join('/') : [host, 'identityiq', interface].join('/'))
72
+ end
73
+
74
+ # Used for fetching the API credentials when setting API requests headers
75
+ # @return [String] - Return a hash of the current API credentils (for validation purposes)
76
+ def credentials
77
+ { username: username, password: password }.freeze
78
+ end
79
+
80
+ # Used for generating the API BasicAuth Header when creating an API request
81
+ # @return [String] - Return the API Authorization header for the making API requests
82
+ def auth_header
83
+ return {}.freeze if username.blank? && password.blank?
84
+
85
+ { 'Authorization' => "Basic #{hashed_credentials}" }.freeze
86
+ end
87
+
88
+ private
89
+
90
+ def reload_config
91
+ ::Sailpoint.mutex.synchronize do
92
+ self.interface ||= 'scim'
93
+ self.host ||= nil
94
+ self.password ||= nil
95
+ self.username ||= nil
96
+ end
97
+ end
98
+
99
+ # Remove trailing forward slashes from the end of the Host, that way hosts and interfaces can be properly joined
100
+ # => I also did this because you'd get the same results if something supplied `http://example.com` or `https://example.com/`
101
+ # @return [String] - Returns a cleaned up and trimmed host with trailing slashs removed
102
+ def trim_host(str = nil)
103
+ return nil if str.blank?
104
+
105
+ str&.strip&.downcase&.gsub(%r{/?++$}, '')
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless defined?(Object.blank?)
4
+ class Object
5
+ def blank?
6
+ respond_to?(:empty?) ? !!empty? : !self
7
+ end
8
+
9
+ def present?
10
+ !blank?
11
+ end
12
+ end
13
+
14
+ # Used to override and give String the blank? validation similar to Rails
15
+ class String
16
+ # Used to determine if the object is nil or empty ('')
17
+ # @return [Boolean]
18
+ def blank?
19
+ strip&.empty? || strip&.length&.zero?
20
+ end
21
+ end
22
+
23
+ # Similar to Rails imlemneation https://github.com/rails/rails/blob/66cabeda2c46c582d19738e1318be8d59584cc5b/activesupport/lib/active_support/core_ext/object/blank.rb#L56
24
+ class NilClass
25
+ # Used to determine if the object is blank? || empty?
26
+ # *Note:* If a nil value is specified it *should* always be blank? || empty?
27
+ # @return [Boolean]
28
+ def blank?
29
+ true
30
+ end
31
+ end
32
+
33
+ # Used to override and give Number the blank? validation similar to Rails
34
+ class Numeric
35
+ # Used to determine if the object is blank? || empty?
36
+ #
37
+ # *Note:* If a object is declared a Numerica valye, it shouldn't ever be blank
38
+ # @return [Boolean]
39
+ def blank?
40
+ false
41
+ end
42
+ end
43
+
44
+ # Used to override and give Array the blank? validation similar to Rails
45
+ class Array
46
+ # Used to determine if the object is blank? || empty?
47
+ # @return [Boolean]
48
+ alias blank? empty?
49
+ end
50
+
51
+ # Used to override and give Hash the blank? validation similar to Rails
52
+ class Hash
53
+ alias blank? empty?
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ class Object
6
+ # In case anything other than a string is called with escape_str
7
+ # @return [String]
8
+ def escape_str
9
+ ''
10
+ end
11
+ end
12
+
13
+ class String
14
+ # Escape any special characters to make them URL safe
15
+ # @return [String]
16
+ def escape_str
17
+ CGI.escape(strip)
18
+ end
19
+ end
20
+
21
+ class NilClass
22
+ # If the identity value was never decalred
23
+ # @return [String]
24
+ def escape_str
25
+ ''
26
+ end
27
+ end
@@ -1,92 +1,28 @@
1
- # Used to override and give String the blank? validation similar to Rails
2
- class String
3
- # Used to determine if the object is nil or empty ('')
4
- # @return [true, false]
5
- def blank?
6
- self.nil? || self.strip.empty? || self.strip.length.zero?
7
- end
8
-
9
- # Used to determine if the object is not nil
10
- # @return [true, false]
11
- def present?
12
- !self.nil?
13
- end
14
-
15
- def escape_str
16
- CGI.escape(self)
17
- end
18
- end
19
-
20
- # Used to printout a [Red] message to STDOUT in case you want to print a message without causing an Exception.
21
- # @param msg [String] - The excpetion message that should be printed out
22
- def print_exception(msg = '')
23
- puts "\e[31m#{msg}\e[0m"
24
- end
25
-
26
- # Similar to Rails imlemneation https://github.com/rails/rails/blob/66cabeda2c46c582d19738e1318be8d59584cc5b/activesupport/lib/active_support/core_ext/object/blank.rb#L56
27
- class NilClass
28
- # Used to determine if the object is blank? || empty?
29
- # *Note:* If a nil value is specified it *should* always be blank? || empty?
30
- # @return [true, false]
31
- def blank?
32
- true
33
- end
34
-
35
- # Used to determine if the object is not nil
36
- # @return [true, false]
37
- def present?
38
- !blank?
1
+ # frozen_string_literal: true
2
+
3
+ module Sailpoint
4
+ class Helpers
5
+ # Used to printout a [Red] message to STDOUT in case you want to print a message without causing an Exception.
6
+ # @param msg [String] - The excpetion message that should be printed out
7
+ def self.print_exception(msg = '')
8
+ puts "\e[31m#{msg}\e[0m"
9
+ end
10
+
11
+ # Used to generate an Exception error hen invalid credentails have been supplied
12
+ class AuthenticationException < StandardError
13
+ attr_reader :data
14
+
15
+ # Used to generate an ExceptionError message when Authenication has failed
16
+ # @param data [String] - The message in which you wish to send to STDOUT for the exception error
17
+ def initialize(data = 'An API Authentication error has occured.')
18
+ super
19
+ @data = data
20
+ end
21
+
22
+ # Specify the attribute in which to push to STDOUT when generating a Ruby ExceptionError
23
+ def message
24
+ @data
25
+ end
26
+ end
39
27
  end
40
28
  end
41
-
42
- # Used to override and give Number the blank? validation similar to Rails
43
- class Numeric
44
- # Used to determine if the object is blank? || empty?
45
- #
46
- # *Note:* If a object is declared a Numerica valye, it shouldn't ever be blank
47
- # @return [true, false]
48
- def blank?
49
- false
50
- end
51
-
52
- # Used to determine if the object is not nil
53
- # @return [true, false]
54
- def present?
55
- !blank?
56
- end
57
- end
58
-
59
- # Used to override and give Array the blank? validation similar to Rails
60
- class Array
61
- # Used to determine if the object is blank? || empty?
62
- # @return [true, false]
63
- alias_method :blank?, :empty?
64
- end
65
-
66
- # Used to override and give Hash the blank? validation similar to Rails
67
- class Hash
68
- alias_method :blank?, :empty?
69
-
70
- # Used to determine if the object is not nil
71
- # @return [true, false]
72
- def present?
73
- !blank?
74
- end
75
- end
76
-
77
- # Used to generate an Exception error hen invalid credentails have been supplied
78
- class AuthenticationException < StandardError
79
- attr_reader :data
80
-
81
- # Used to generate an ExceptionError message when Authenication has failed
82
- # @param data [String] - The message in which you wish to send to STDOUT for the exception error
83
- def initialize(data = 'An API Authentication error has occured.')
84
- super
85
- @data = data
86
- end
87
-
88
- # Specify the attribute in which to push to STDOUT when generating a Ruby ExceptionError
89
- def message
90
- @data
91
- end
92
- end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'httparty'
2
4
  require 'json'
3
5
 
@@ -5,12 +7,16 @@ require 'json'
5
7
  module Sailpoint
6
8
  # Used for created REST API calls to the organizations IdentityIQ source
7
9
  class Rest
10
+ EMPTY_RESPONSE = '{}'
11
+ EMPTY_HASH = {}.freeze
12
+
8
13
  # Used to verify if the supplied credentials are valid
9
14
  # @return [Hash] - The responses body as a JSON hash
10
15
  def self.authenticate
11
- response = HTTParty.get([Sailpoint::Config.url('rest'), 'authentication'].join('/'),
12
- headers: Sailpoint::Config.auth_header,
13
- output: 'json')
16
+ set_rest_interface
17
+ response = HTTParty.get([Sailpoint.config.url, 'authentication'].join('/'),
18
+ headers: Sailpoint.config.auth_header,
19
+ output: 'json', timeout: 10)
14
20
  JSON.parse(response)
15
21
  end
16
22
 
@@ -21,61 +27,76 @@ module Sailpoint
21
27
  def self.check_roles(identity, roles)
22
28
  # Values for both attributes are required in order to create the request
23
29
  # And verify the user exists before attempting to create the request (this prevents IdentityIQ from making a long last query looking for a non-existant user)
24
- return {} if identity.blank? || roles.blank? || get_user(identity).empty?
30
+ return EMPTY_HASH if identity.blank? || roles.blank? || get_user(identity).empty?
25
31
 
32
+ set_rest_interface
26
33
  # the roles attribute should either be 'Contractor,Assistant' or ['Contractor', 'Assistant']
27
34
  roles = roles.join(',') if roles.is_a?(Array)
28
- response = HTTParty.get([Sailpoint::Config.url('rest'), "policies/checkRolePolicies?identity=#{identity.escape_str}&roles=#{roles}"].join('/'),
29
- headers: Sailpoint::Config.auth_header,
30
- output: 'json')
31
- JSON.parse(response&.body || '{}')
35
+ response = HTTParty.get([Sailpoint.config.url, "policies/checkRolePolicies?identity=#{identity&.escape_str}&roles=#{roles}"].join('/'),
36
+ headers: Sailpoint.config.auth_header,
37
+ output: 'json', timeout: 10)
38
+ JSON.parse(response&.body || EMPTY_RESPONSE)
32
39
  end
33
40
 
34
41
  # Used to fetch the specified user identiy from the REST API interface
35
42
  # @param identity [String] - The user in which you are requesting data for
36
43
  # @return [Hash] - If no user if found an empty hash will be returned. If a a user is found, their parsed JSON will be returned as a result
37
44
  def self.get_identity(identity)
38
- response = HTTParty.get([Sailpoint::Config.url('rest'), 'identities', identity.escape_str, 'managedIdentities'].join('/'),
39
- headers: Sailpoint::Config.auth_header,
45
+ set_rest_interface
46
+ response = HTTParty.get([Sailpoint.config.url, 'identities', identity&.escape_str, 'managedIdentities'].join('/'),
47
+ headers: Sailpoint.config.auth_header,
40
48
  output: 'json', timeout: 10)
41
- return [] if response.code == '500'
49
+ return [].freeze if response.code == '500'
42
50
 
43
- JSON.parse(response&.body || '{}').first
51
+ JSON.parse(response&.body || EMPTY_RESPONSE).first
44
52
  end
45
53
 
46
54
  # Used to fetch the specified users associated data
47
55
  # @param identity [String] - The user in which you are requesting data for
48
56
  # @return [Hash] - If no user if found an empty hash will be returned. If a a user is found, their parsed JSON will be returned as a result
49
57
  def self.get_user(identity)
50
- response = HTTParty.get([Sailpoint::Config.url('rest'), 'identities', identity.escape_str].join('/'),
51
- headers: Sailpoint::Config.auth_header,
58
+ set_rest_interface
59
+ response = HTTParty.get([Sailpoint.config.url, 'identities', identity&.escape_str].join('/'),
60
+ headers: Sailpoint.config.auth_header,
52
61
  output: 'json', timeout: 10)
53
- raise AuthenticationException, 'Invalid credentials, please try again.' if response.code == 401
62
+ raise Sailpoint::Helpers::AuthenticationException, 'Invalid credentials, please try again.' if response.code == 401
54
63
 
55
- JSON.parse(response&.body || '{}')
64
+ JSON.parse(response&.body || EMPTY_RESPONSE)
56
65
  end
57
66
 
58
67
  # Get a users roles within the Organization
59
68
  # @return [Hash] - The users roles associated within the Organization
60
- def self.permitted_roles(identity)
69
+ def self.permitted_roles(identity = '')
61
70
  # Before requesting a users roles we need to verify if the identiy matches a valid user first
62
- return {} if identity.blank? || get_user(identity).empty?
71
+ return EMPTY_HASH if identity.blank? || get_user(identity).blank?
63
72
 
64
- response = HTTParty.get([Sailpoint::Config.url('rest'), "roles/assignablePermits/?roleMode=assignable&identity=#{identity.escape_str}"].join('/'),
65
- headers: Sailpoint::Config.auth_header,
73
+ set_rest_interface
74
+ response = HTTParty.get([Sailpoint.config.url, "roles/assignablePermits/?roleMode=assignable&identity=#{identity&.escape_str}"].join('/'),
75
+ headers: Sailpoint.config.auth_header,
66
76
  output: 'json', timeout: 10)
67
- response_body = JSON.parse(response&.body || '{}')
77
+ response_body = JSON.parse(response&.body || EMPTY_RESPONSE)
68
78
  return response_body['objects'].map { |role| role['name'] } if response['status'].present? && response['status'] == 'success'
69
79
 
70
80
  response_body
81
+ rescue
82
+ EMPTY_HASH
71
83
  end
72
84
 
73
85
  # Used to verify your credentials are valid and IdentityIQ reource is properly responding
74
86
  # @return [Hash] - The head and body of the response
75
87
  def self.ping
76
- HTTParty.get([Sailpoint::Config.url('rest'), 'ping'].join('/'),
77
- headers: Sailpoint::Config.auth_header,
88
+ set_rest_interface
89
+ HTTParty.get([Sailpoint.config.url, 'ping'].join('/'),
90
+ headers: Sailpoint.config.auth_header,
78
91
  output: 'json', timeout: 10)
92
+ rescue
93
+ false
79
94
  end
95
+
96
+ def self.set_rest_interface
97
+ Sailpoint.config.interface = 'rest'
98
+ end
99
+
100
+ private_class_method :set_rest_interface
80
101
  end
81
102
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'httparty'
2
4
  require 'json'
3
5
 
@@ -5,81 +7,97 @@ require 'json'
5
7
  module Sailpoint
6
8
  # Used for created SCIM API calls to the organizations IdentityIQ source
7
9
  class Scim
10
+ EMPTY_RESPONSE = '{}'
11
+
8
12
  # Returns a massive list of all account entries in the IdeneityIQ sources
9
13
  # @return [Hash] - A hashed list of all IdenityIQ accounts [Service and User accounts]
10
14
  def self.accounts
11
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/Accounts'].join('/'),
12
- headers: Sailpoint::Config.auth_header,
15
+ set_scim_interface
16
+ response = HTTParty.get([Sailpoint.config.url, 'v2/Accounts'].join('/'),
17
+ headers: Sailpoint.config.auth_header,
13
18
  output: 'json', timeout: 10)
14
- JSON.parse(response&.body || '{}')
19
+ JSON.parse(response&.body || EMPTY_RESPONSE)
15
20
  end
16
21
 
17
22
  # Used to fetch a list of all Applications and their associated attributes
18
23
  # @return [Hash] - A hash of all avaialble applications and their associated MetaData attributes
19
24
  def self.applications
20
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/Applications'].join('/'),
21
- headers: Sailpoint::Config.auth_header,
25
+ set_scim_interface
26
+ response = HTTParty.get([Sailpoint.config.url, 'v2/Applications'].join('/'),
27
+ headers: Sailpoint.config.auth_header,
22
28
  output: 'json', timeout: 10)
23
- JSON.parse(response&.body || '{}')
29
+ JSON.parse(response&.body || EMPTY_RESPONSE)
24
30
  end
25
31
 
26
32
  # Used to fetch the specified users associated data
27
33
  # @return [Hash] - The users hashed data attributes
28
34
  def self.get_user(identity)
29
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/Users', identity.escape_str].join('/'),
30
- headers: Sailpoint::Config.auth_header,
35
+ set_scim_interface
36
+ response = HTTParty.get([Sailpoint.config.url, 'v2/Users', identity].join('/'),
37
+ headers: Sailpoint.config.auth_header,
31
38
  output: 'json', timeout: 10)
32
39
  # NOTE: If invalid credentials are supplied or the user could not be found response bodies contain a status code.
33
40
  # => But if a a user if found, a status code isn't returned, but all of their data attributes are returned instead.
34
- raise AuthenticationException, 'Invalid credentials, please try again.' if response.body['status'] && response.body['status'] == '401'
35
- return [] if response.body && response.body['status'] && response.body['status'] == '404'
41
+ raise Sailpoint::Helpers::AuthenticationException, 'Invalid credentials, please try again.' if response.body['status'] && response.body['status'] == '401'
42
+ return [].freeze if response.body && response.body['status'] && response.body['status'] == '404'
36
43
 
37
- JSON.parse(response&.body || '{}')
44
+ JSON.parse(response&.body || EMPTY_RESPONSE)
38
45
  end
39
46
 
40
47
  # Fetch all resource types associated with the IdentityIQ API
41
48
  # @return [Hash] - A hash of all resources types [Users, Applications, Accounts, Roles, etc.]
42
49
  def self.resource_types
43
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/ResourceTypes'].join('/'),
44
- headers: Sailpoint::Config.auth_header,
50
+ set_scim_interface
51
+ response = HTTParty.get([Sailpoint.config.url, 'v2/ResourceTypes'].join('/'),
52
+ headers: Sailpoint.config.auth_header,
45
53
  output: 'json', timeout: 10)
46
- JSON.parse(response&.body || '{}')
54
+ JSON.parse(response&.body || EMPTY_RESPONSE)
47
55
  end
48
56
 
49
57
  # Fetch the schemas for all resources types assocaited with the API's returning data
50
58
  # @return [Hash] - A hash of all all ResourceType Schemas
51
59
  def self.schemas
52
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/Schemas'].join('/'),
53
- headers: Sailpoint::Config.auth_header,
60
+ set_scim_interface
61
+ response = HTTParty.get([Sailpoint.config.url, 'v2/Schemas'].join('/'),
62
+ headers: Sailpoint.config.auth_header,
54
63
  output: 'json', timeout: 10)
55
- JSON.parse(response&.body || '{}')
64
+ JSON.parse(response&.body || EMPTY_RESPONSE)
56
65
  end
57
66
 
58
67
  # Fetch a list of all ServiceProviders associated with the data being served by the API
59
68
  # @return [Hash] - A hashed list of SailPoint service providers associated with the IdentityIQ Instance
60
69
  def self.service_providers
61
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/ServiceProviderConfig'].join('/'),
62
- headers: Sailpoint::Config.auth_header,
70
+ set_scim_interface
71
+ response = HTTParty.get([Sailpoint.config.url, 'v2/ServiceProviderConfig'].join('/'),
72
+ headers: Sailpoint.config.auth_header,
63
73
  output: 'json', timeout: 10)
64
- JSON.parse(response&.body || '{}')
74
+ JSON.parse(response&.body || EMPTY_RESPONSE)
65
75
  end
66
76
 
67
77
  # Returns a list of all users from the associated organizations
68
78
  # @return [Hash] - All users entries from the organizations sources
69
79
  def self.users
70
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/Users'].join('/'),
71
- headers: Sailpoint::Config.auth_header,
80
+ set_scim_interface
81
+ response = HTTParty.get([Sailpoint.config.url, 'v2/Users'].join('/'),
82
+ headers: Sailpoint.config.auth_header,
72
83
  output: 'json', timeout: 10)
73
- JSON.parse(response&.body || '{}')
84
+ JSON.parse(response&.body || EMPTY_RESPONSE)
74
85
  end
75
86
 
76
87
  # Returns a list of data attributes for the ResourceType -> Users
77
88
  # @return [Hash] - A hash to describe the user schema attributes
78
89
  def self.user_resource_types
79
- response = HTTParty.get([Sailpoint::Config.url('scim'), 'v2/ResourceTypes/User'].join('/'),
80
- headers: Sailpoint::Config.auth_header,
90
+ set_scim_interface
91
+ response = HTTParty.get([Sailpoint.config.url, 'v2/ResourceTypes/User'].join('/'),
92
+ headers: Sailpoint.config.auth_header,
81
93
  output: 'json', timeout: 10)
82
- JSON.parse(response&.body || '{}')
94
+ JSON.parse(response&.body || EMPTY_RESPONSE)
83
95
  end
96
+
97
+ def self.set_scim_interface
98
+ Sailpoint.config.interface = 'scim'
99
+ end
100
+
101
+ private_class_method :set_scim_interface
84
102
  end
85
103
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sailpoint
2
4
  # The minimum required RUBY_VERSION
3
- RUBY_VERSION = '2.5'.freeze
4
- # The Sailpoints version
5
- VERSION = '0.0.3'.freeze
5
+ RUBY_VERSION = '2.5'
6
+ VERSION = '0.1.0'
6
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sailpoint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Hicks
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-16 00:00:00.000000000 Z
11
+ date: 2021-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.17.0
19
+ version: '0.18'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.17.0
26
+ version: '0.18'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,29 +50,29 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '10.0'
53
+ version: '13'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '10.0'
60
+ version: '13'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rspec
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 3.8.0
67
+ version: '3.9'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 3.8.0
75
- description:
74
+ version: '3.9'
75
+ description: An helper for making API requests to a Sailpoint/IdentityIQ APIendpoint
76
76
  email:
77
77
  - tarellel@gmail.com
78
78
  executables: []
@@ -86,16 +86,21 @@ files:
86
86
  - bin/console
87
87
  - bin/setup
88
88
  - lib/sailpoint.rb
89
- - lib/sailpoint/config.rb
89
+ - lib/sailpoint/configuration.rb
90
+ - lib/sailpoint/core_ext/blank.rb
91
+ - lib/sailpoint/core_ext/escape_str.rb
90
92
  - lib/sailpoint/helpers.rb
91
93
  - lib/sailpoint/rest.rb
92
94
  - lib/sailpoint/scim.rb
93
95
  - lib/sailpoint/version.rb
94
- homepage:
96
+ homepage: https://github.com/tarellel/sailpoint
95
97
  licenses:
96
98
  - MIT
97
- metadata: {}
98
- post_install_message:
99
+ metadata:
100
+ bug_tracker_uri: https://github.com/tarellel/sailpoint/issues
101
+ changelog_uri: https://github.com/tarellel/sailpoint/blob/master/CHANGELOG.md
102
+ source_code_uri: https://github.com/tarellel/sailpoint
103
+ post_install_message:
99
104
  rdoc_options: []
100
105
  require_paths:
101
106
  - lib
@@ -110,8 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
115
  - !ruby/object:Gem::Version
111
116
  version: '0'
112
117
  requirements: []
113
- rubygems_version: 3.0.6
114
- signing_key:
118
+ rubygems_version: 3.2.3
119
+ signing_key:
115
120
  specification_version: 4
116
121
  summary: A Sailpoint API helper
117
122
  test_files: []
@@ -1,105 +0,0 @@
1
- require 'base64'
2
- require 'sailpoint/helpers'
3
-
4
- # Used for setting you Sailpoint API configuration and credentials
5
- module Sailpoint
6
- # Used for setting API configuration before creating API Requests
7
- # Configuration can include: <code>username, password, interface, host, url</code>
8
- class Config
9
- attr_accessor :username, :password, :interface, :url
10
-
11
- @username = nil
12
- @password = nil
13
- @interface = 'rest' # By default lets resort to using the Rest interface
14
- @host = nil # Where the SailPoint server is hosted
15
-
16
- class << self
17
- attr_writer :username, :password, :interface, :host, :url
18
-
19
- # Used to set the API requests BasicAuth credentails
20
- # @param username [String] - Username for the API request
21
- # @param password [String] - Password for the API request
22
- def set_credentials(username, password)
23
- @username = username unless username.nil?
24
- @password = password unless password.nil?
25
- end
26
-
27
- # Used for setting if the interface type is Rest || SCIM
28
- # @return [String] - Returns either the specified interface (Default: <code>rest</code>)
29
- def interface
30
- (@interface ||= 'rest')
31
- end
32
-
33
- # Used for fetching the API interface_path based on the API interface specification
34
- # @return [String] - Returns the API's interface path, based on interface type
35
- def interface_path
36
- (@interface == 'scim' ? 'scim' : 'rest')
37
- end
38
-
39
- # Used to fetch the host for the API request
40
- # @return [String] - If a valid host was specified, it will returned a trimmed string with trailing whitespaces and slashes removed
41
- def host
42
- return '' if @host.blank?
43
-
44
- trimmed_host
45
- end
46
-
47
- # Used for fetching the requesting users entire URL (Host+Interface)
48
- # @param interface [String] - used for when the user is specicically calling an API such as <code>Unmh::Sailpoint::Scim.get_user('brhicks')</code>
49
- # @return [String] - Returns the entire requesting URL (based on host and interface type)
50
- def url(interface = '')
51
- return '' if @host.blank? || @interface.blank?
52
-
53
- full_host(interface)
54
- end
55
-
56
- def full_host(interface = '')
57
- interface.blank? ? [trimmed_host, 'identityiq', interface_path].join('/') : [trimmed_host, 'identityiq', interface].join('/')
58
- end
59
-
60
- # Used for fetching credentails username (if it has been set)
61
- # @return [String] - The credentails username
62
- def username
63
- @username || ''
64
- end
65
-
66
- # Used for fetching the requesting users credentials password (if it has been set)
67
- # @return [String] - The password for the API credentials
68
- def password
69
- @password || ''
70
- end
71
-
72
- # Used for fetching the API credentials when setting API requests headers
73
- # @return [String] - Return a hash of the current API credentils (for validation purposes)
74
- def credentials
75
- { username: @username, password: @password }
76
- end
77
-
78
- # Remove trailing forward slashes from the end of the Host, that way hosts and interfaces can be properly joined
79
- # => I also did this because you'd get the same results if something supplied `http://example.com` or `https://example.com/`
80
- # @return [String] - Returns a cleaned up and trimmed host with trailing slashs removed
81
- def trimmed_host
82
- return '' if @host.blank?
83
-
84
- @host.strip.gsub!(%r{\/?++$}, '')
85
- end
86
-
87
- # SailPoints auth requires a Base64 string of (username:password)
88
- # This is how most BasicAuth authentication methods work
89
- # @return [String] - It will either return an empty string or a Base64.encoded hash for the the API credentials (BasicAuth requires Base64)
90
- def hashed_credentials
91
- return '' if @username.blank? && @password.blank?
92
-
93
- Base64.encode64("#{@username}:#{@password}").strip
94
- end
95
-
96
- # Used for generating the API BasicAuth Header when creating an API request
97
- # @return [String] - Return the API Authorization header for the making API requests
98
- def auth_header
99
- return '' if @username.blank? && @password.blank?
100
-
101
- { 'Authorization' => "Basic #{Sailpoint::Config.hashed_credentials}" }
102
- end
103
- end
104
- end
105
- end