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 +4 -4
- data/README.md +35 -37
- data/lib/sailpoint.rb +54 -44
- data/lib/sailpoint/configuration.rb +108 -0
- data/lib/sailpoint/core_ext/blank.rb +55 -0
- data/lib/sailpoint/core_ext/escape_str.rb +27 -0
- data/lib/sailpoint/helpers.rb +26 -90
- data/lib/sailpoint/rest.rb +44 -23
- data/lib/sailpoint/scim.rb +44 -26
- data/lib/sailpoint/version.rb +4 -3
- metadata +21 -16
- data/lib/sailpoint/config.rb +0 -105
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1220fcec1f06178a2d7a3ad3223c4f8a142c97a1c5c22a1a04cc7d0534fc2969
|
4
|
+
data.tar.gz: 0f4937b7f5a97782a0b2f0a86d7e09f621c196a33576c6149df973aa209ab9fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
50
|
-
|
51
|
-
|
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'
|
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::
|
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
|
80
|
-
|
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
|
86
|
-
|
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
|
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
|
116
|
-
* `Sailpoint
|
117
|
-
* `Sailpoint
|
118
|
-
* `Sailpoint
|
119
|
-
* `Sailpoint
|
120
|
-
* `Sailpoint
|
121
|
-
* `Sailpoint
|
122
|
-
* `Sailpoint
|
123
|
-
* `Sailpoint
|
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/)
|
data/lib/sailpoint.rb
CHANGED
@@ -1,61 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sailpoint/version'
|
2
|
-
require 'sailpoint/
|
3
|
-
require 'sailpoint/
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
47
|
-
|
48
|
+
!Sailpoint.config.hashed_credentials.blank?
|
49
|
+
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
data/lib/sailpoint/helpers.rb
CHANGED
@@ -1,92 +1,28 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
data/lib/sailpoint/rest.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
13
|
-
|
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
|
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
|
29
|
-
headers: Sailpoint
|
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
|
-
|
39
|
-
|
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 ||
|
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
|
-
|
51
|
-
|
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
|
71
|
+
return EMPTY_HASH if identity.blank? || get_user(identity).blank?
|
63
72
|
|
64
|
-
|
65
|
-
|
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
|
-
|
77
|
-
|
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
|
data/lib/sailpoint/scim.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
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
|
-
|
21
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
44
|
-
|
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
|
-
|
53
|
-
|
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
|
-
|
62
|
-
|
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
|
-
|
71
|
-
|
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
|
-
|
80
|
-
|
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
|
data/lib/sailpoint/version.rb
CHANGED
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
|
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:
|
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.
|
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.
|
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: '
|
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: '
|
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.
|
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.
|
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/
|
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
|
-
|
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.
|
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: []
|
data/lib/sailpoint/config.rb
DELETED
@@ -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
|