sailpoint 0.0.3 → 0.1.0

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