idnio 2.3.2b
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/idnio.rb +295 -0
- data/lib/idnio/crypto.rb +34 -0
- data/lib/idnio/idnapi.rb +158 -0
- data/lib/idnio/markdown.rb +345 -0
- data/lib/idnio/program.rb +153 -0
- data/lib/idnio/timer.rb +57 -0
- data/lib/idnio/version.rb +4 -0
- data/lib/objects/access-profiles.rb +107 -0
- data/lib/objects/access-request-config.rb +90 -0
- data/lib/objects/account-profiles.rb +167 -0
- data/lib/objects/account-schemas.rb +341 -0
- data/lib/objects/applications.rb +145 -0
- data/lib/objects/attribute-sync-config.rb +122 -0
- data/lib/objects/branding.rb +49 -0
- data/lib/objects/campaign-filters.rb +61 -0
- data/lib/objects/connectors.rb +291 -0
- data/lib/objects/email-templates.rb +226 -0
- data/lib/objects/identity-attributes.rb +136 -0
- data/lib/objects/identity-profiles.rb +206 -0
- data/lib/objects/integrations.rb +149 -0
- data/lib/objects/lifecycle-states.rb +86 -0
- data/lib/objects/password-policies.rb +107 -0
- data/lib/objects/password-sync-groups.rb +100 -0
- data/lib/objects/public-identities-config.rb +78 -0
- data/lib/objects/reference-resolver.rb +137 -0
- data/lib/objects/roles.rb +117 -0
- data/lib/objects/rules.rb +198 -0
- data/lib/objects/sources.rb +217 -0
- data/lib/objects/system-settings.rb +185 -0
- data/lib/objects/transforms.rb +157 -0
- metadata +124 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "json"
|
3
|
+
require "idnio/idnapi"
|
4
|
+
require "idnio/program"
|
5
|
+
|
6
|
+
module ReferenceResolver
|
7
|
+
|
8
|
+
@@default_identity_ref = nil
|
9
|
+
|
10
|
+
@@default_cluster_ref = nil
|
11
|
+
|
12
|
+
def self.get_default_identity_ref
|
13
|
+
if @@default_identity_ref.nil?
|
14
|
+
@@default_identity_ref = ReferenceResolver.get_identity_ref( "slpt.services" )
|
15
|
+
end
|
16
|
+
return @@default_identity_ref
|
17
|
+
end #def self.get_default_identity_ref
|
18
|
+
|
19
|
+
def self.get_identity_ref( name )
|
20
|
+
|
21
|
+
query = {
|
22
|
+
"queryType": "SAILPOINT",
|
23
|
+
"query": {
|
24
|
+
"query": "name:#{name}"
|
25
|
+
}
|
26
|
+
}
|
27
|
+
response = IDNAPI.post_json( "#{$url}/beta/search/identities?count=true&offset=0&limit=1", $token, query )
|
28
|
+
|
29
|
+
unless response['X-Total-Count'].nil?
|
30
|
+
count = response['X-Total-Count'].to_i
|
31
|
+
|
32
|
+
if count == 1 # Make sure we have a unique result.
|
33
|
+
|
34
|
+
identities = JSON.parse( response.body )
|
35
|
+
|
36
|
+
identity = identities.first
|
37
|
+
|
38
|
+
identity_ref = {
|
39
|
+
"type": "IDENTITY",
|
40
|
+
"id": identity['id'],
|
41
|
+
"name": identity['name']
|
42
|
+
}
|
43
|
+
|
44
|
+
return identity_ref
|
45
|
+
|
46
|
+
elsif name != "slpt.services" # We don't have a unique result, and we're not looking up slpt.services, so we'll look that up instead.
|
47
|
+
|
48
|
+
$log.debug "\t\tCannot resolve unique identity '#{name}'. Resolving identity 'slpt.services' instead."
|
49
|
+
return ReferenceResolver.get_default_identity_ref
|
50
|
+
|
51
|
+
else # We don't have a unique result, and we couldn't resolve anything else. Punt. Hopefully we never see this message.
|
52
|
+
|
53
|
+
$log.debug "\t\tCannot resolve identity '#{name}' . Giving up with no identity."
|
54
|
+
return nil
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end # if response['X-Total-Count'].nil?
|
59
|
+
|
60
|
+
return nil # catch all.
|
61
|
+
|
62
|
+
end # def self.get_identity_ref ( name )
|
63
|
+
|
64
|
+
def self.get_default_cluster_ref
|
65
|
+
|
66
|
+
if @@default_cluster_ref.nil?
|
67
|
+
|
68
|
+
response = IDNAPI.get( "#{$url}/cc/api/cluster/list", $token )
|
69
|
+
|
70
|
+
case response
|
71
|
+
when Net::HTTPSuccess
|
72
|
+
|
73
|
+
clusters = JSON.parse( response.body )
|
74
|
+
|
75
|
+
unless clusters.nil? || clusters.empty?
|
76
|
+
|
77
|
+
cluster = clusters.first
|
78
|
+
|
79
|
+
cluster_ref = {
|
80
|
+
"type": "CLUSTER",
|
81
|
+
"id": "#{cluster['configuration']['clusterExternalId']}",
|
82
|
+
"name": "#{cluster['name']}"
|
83
|
+
}
|
84
|
+
|
85
|
+
@@default_cluster_ref = cluster_ref
|
86
|
+
|
87
|
+
end #unless clusters["items"].nil?
|
88
|
+
|
89
|
+
else
|
90
|
+
$log.error "\tError: Unable to fetch clusters."
|
91
|
+
end # case response
|
92
|
+
|
93
|
+
end # if @@default_cluster_ref.nil?
|
94
|
+
|
95
|
+
return @@default_cluster_ref
|
96
|
+
|
97
|
+
end # def self.get_default_cluster_ref
|
98
|
+
|
99
|
+
def self.get_cluster_ref( name )
|
100
|
+
|
101
|
+
response = IDNAPI.get( "#{$url}/cc/api/cluster/list", $token )
|
102
|
+
|
103
|
+
case response
|
104
|
+
when Net::HTTPSuccess
|
105
|
+
|
106
|
+
clusters = JSON.parse( response.body )
|
107
|
+
|
108
|
+
unless clusters.nil? || clusters.empty?
|
109
|
+
|
110
|
+
clusters.each do |cluster|
|
111
|
+
|
112
|
+
# If we match the name of the cluster we are looking for.
|
113
|
+
if cluster['name'] == name
|
114
|
+
|
115
|
+
cluster_ref = {
|
116
|
+
"type": "CLUSTER",
|
117
|
+
"id": "#{cluster['configuration']['clusterExternalId']}",
|
118
|
+
"name": "#{cluster['name']}"
|
119
|
+
}
|
120
|
+
return cluster_ref
|
121
|
+
|
122
|
+
end # if cluster['name'] == name
|
123
|
+
|
124
|
+
end # clusters.each do |cluster|
|
125
|
+
|
126
|
+
end # unless clusters["items"].nil?
|
127
|
+
|
128
|
+
else
|
129
|
+
$log.error "\tError: Unable to fetch clusters."
|
130
|
+
end # case response
|
131
|
+
|
132
|
+
$log.warn "\tUnable to find a cluster which matches name #{name}."
|
133
|
+
|
134
|
+
return nil
|
135
|
+
|
136
|
+
end # def self.get_cluster_ref( name )
|
137
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "json"
|
3
|
+
require "csv"
|
4
|
+
require "idnio/idnapi"
|
5
|
+
require "idnio/program"
|
6
|
+
require "idnio/markdown"
|
7
|
+
|
8
|
+
module Roles
|
9
|
+
|
10
|
+
def self.querysearch( query )
|
11
|
+
|
12
|
+
response = IDNAPI.get( "#{$url}/v2/search/roles?offset=0&limit=10&query=#{query}", $token )
|
13
|
+
|
14
|
+
case response
|
15
|
+
when Net::HTTPSuccess
|
16
|
+
|
17
|
+
roles = JSON.parse( response.body )
|
18
|
+
|
19
|
+
unless roles.nil? || roles.empty?
|
20
|
+
return roles.first
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
return nil
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Exports Role configurations.
|
31
|
+
#
|
32
|
+
def self.export( directory )
|
33
|
+
|
34
|
+
response = IDNAPI.get( "#{$url}/cc/api/role/list", $token )
|
35
|
+
|
36
|
+
unless response.nil?
|
37
|
+
|
38
|
+
roles = JSON.parse( response.body )
|
39
|
+
|
40
|
+
$log.info "\tDetected #{roles['count']} roles."
|
41
|
+
|
42
|
+
roles['items'].each do |role|
|
43
|
+
|
44
|
+
apNames = ""
|
45
|
+
|
46
|
+
$log.info "\tRole: #{role["displayName"]}"
|
47
|
+
|
48
|
+
role_response = IDNAPI.get( "#{$url}/cc/api/role/get/?id=#{role["id"]}", $token )
|
49
|
+
|
50
|
+
full_role = JSON.parse( role_response.body )
|
51
|
+
|
52
|
+
full_role['accessProfileIds'].each do |ap|
|
53
|
+
|
54
|
+
response = IDNAPI.get( "#{$url}/v2/search/accessprofiles?query='id=#{ap}''", $token )
|
55
|
+
|
56
|
+
unless response.nil?
|
57
|
+
result = JSON.parse( response.body )
|
58
|
+
result.each do |r|
|
59
|
+
|
60
|
+
apNames << r['name']
|
61
|
+
apNames << ";"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
full_role['accessProfileNames'] = apNames
|
66
|
+
|
67
|
+
Program.write_file( "#{directory}/roles/", "Role - #{full_role["displayName"]}.json", JSON.pretty_generate(full_role) )
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Import Role configurations.
|
74
|
+
#
|
75
|
+
def self.import( directory )
|
76
|
+
$log.warn "\tImport for object type roles is not supported at this time."
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Documents Role configurations.
|
81
|
+
#
|
82
|
+
def self.doc
|
83
|
+
Markdown.h2( "Roles" )
|
84
|
+
|
85
|
+
Markdown.text( "| Name | Description | Selector | Access Profiles |\n")
|
86
|
+
Markdown.text( "|------|-------------|----------|-----------------|\n")
|
87
|
+
|
88
|
+
response = IDNAPI.get( "#{$url}/cc/api/role/list", $token )
|
89
|
+
unless response.nil?
|
90
|
+
roles = JSON.parse( response.body )
|
91
|
+
|
92
|
+
$log.info "\tDetected #{roles['count']} roles."
|
93
|
+
|
94
|
+
roles['items'].each do |role|
|
95
|
+
$log.info "\tRole: #{role["displayName"]}"
|
96
|
+
role_response = IDNAPI.get( "#{$url}/cc/api/role/get/?id=#{role["id"]}", $token )
|
97
|
+
full_role = JSON.parse( role_response.body )
|
98
|
+
search_role = Roles.querysearch( "name:\"#{role["displayName"]}\"" )
|
99
|
+
accessProfileNames = ""
|
100
|
+
|
101
|
+
unless search_role["accessProfiles"].nil?
|
102
|
+
search_role["accessProfiles"].each do |ap|
|
103
|
+
if accessProfileNames != ""
|
104
|
+
accessProfileNames += ","
|
105
|
+
end
|
106
|
+
accessProfileNames += ap["name"]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
#end
|
110
|
+
Markdown.text( "|#{full_role["displayName"]}|#{full_role["description"]}|#{full_role["selector"]}|#{accessProfileNames}|\n")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Markdown.write
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "json"
|
3
|
+
require "idnio/idnapi"
|
4
|
+
require "idnio/program"
|
5
|
+
require "idnio/markdown"
|
6
|
+
|
7
|
+
module Rules
|
8
|
+
|
9
|
+
@@default_rules = [
|
10
|
+
"AccessIQ Add Usage Certification",
|
11
|
+
"Account Report Form Customizer",
|
12
|
+
"Active Directory Customization",
|
13
|
+
"After Operation Rule Template for Web Services",
|
14
|
+
"All Objects",
|
15
|
+
"Approval Library",
|
16
|
+
"Azure AD Customization",
|
17
|
+
"Before Operation Rule Template for Web Services Connector",
|
18
|
+
"Build Manual Action Approvals",
|
19
|
+
"CEFActivityCorrelation",
|
20
|
+
"CEFTransformRule",
|
21
|
+
"Certification Report Customizer",
|
22
|
+
"Check Password Policy",
|
23
|
+
"Clear CustomGlobal",
|
24
|
+
"Cloud Account Attribute Transform",
|
25
|
+
"Cloud Account Group Refresh Rule",
|
26
|
+
"Cloud Active Phase Enter Rule",
|
27
|
+
"Cloud Approval Escalation Rule",
|
28
|
+
"Cloud Calculate Authentication Alias",
|
29
|
+
"Cloud Calculate Identity Status",
|
30
|
+
"Cloud Calculate Internal Identity Status",
|
31
|
+
"Cloud Cert Item Customization Rule",
|
32
|
+
"Cloud Certification Reassignment Rule",
|
33
|
+
"Cloud Clone Existing Account",
|
34
|
+
"Cloud Correlate Manager by AccountId",
|
35
|
+
"Cloud Detect Lifecycle State Change",
|
36
|
+
"Cloud End Phase Enter Rule",
|
37
|
+
"Cloud Flat File CustomizationRule",
|
38
|
+
"Cloud Identity Refresh Rule",
|
39
|
+
"Cloud Identity Tester",
|
40
|
+
"Cloud Promote Identity Attribute",
|
41
|
+
"CMS Cert Item Customization Rule",
|
42
|
+
"CMS Certification Reassignment Rule",
|
43
|
+
"CMS Execute Campaign Filter",
|
44
|
+
"Correct Link Idx Column",
|
45
|
+
"Create Password",
|
46
|
+
"Create Unique Account ID",
|
47
|
+
"Create Unique LDAP Attribute",
|
48
|
+
"Exclude Uncorrelated Identities",
|
49
|
+
"Execute Campaign Filter",
|
50
|
+
"Get Manager LDAP DN",
|
51
|
+
"Identity Report Form Customizer",
|
52
|
+
"IdentityNowSAML",
|
53
|
+
"JDBCProvisioning Rule Adapter",
|
54
|
+
"LCM Build Identity ApprovalSet",
|
55
|
+
"LCM Build Identity Approvers",
|
56
|
+
"LCM Build Owner Approvals",
|
57
|
+
"LCM Validate Identity Name",
|
58
|
+
"LCM Validate Password",
|
59
|
+
"LCM Workflow Library",
|
60
|
+
"Microsoft Office365 Customization",
|
61
|
+
"No Correlator",
|
62
|
+
"Objects in Requestee's Assigned Scope",
|
63
|
+
"Objects in Requestor's Authorized Scopes",
|
64
|
+
"Objects in Requestor's Authorized Scopes or Requestee's Assigned Scope",
|
65
|
+
"Objects Owned by the Requestor",
|
66
|
+
"Privileged Access Report Customizer",
|
67
|
+
"Privileged Access Report Validation Rule",
|
68
|
+
"Report Completion Notification",
|
69
|
+
"Report Scorecard Value Renderer",
|
70
|
+
"SuccessFactorsOperationProvisioning",
|
71
|
+
"System Configured Locale Rule",
|
72
|
+
"Task Completion Email Rule",
|
73
|
+
"WindowsActivityRuleLibrary",
|
74
|
+
"Workflow Library"
|
75
|
+
]
|
76
|
+
|
77
|
+
#
|
78
|
+
# Get Rule XML
|
79
|
+
#
|
80
|
+
def self.get_xml( rule )
|
81
|
+
|
82
|
+
if rule.nil?
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
|
86
|
+
rule_xml = "<?xml version='1.0' encoding='UTF-8'?>\n<!DOCTYPE Rule PUBLIC 'sailpoint.dtd' 'sailpoint.dtd'>\n<Rule language='beanshell' name='#{rule['name']}'"
|
87
|
+
|
88
|
+
unless rule['type'].nil?
|
89
|
+
rule_xml += " type='#{rule['type']}' "
|
90
|
+
end
|
91
|
+
|
92
|
+
unless rule['description'].nil?
|
93
|
+
rule_description = rule['description'].gsub(/\t+|\s+/," ").gsub(/(\r\n)+|\r+|^\s+|\s+$|\n+?/,"")
|
94
|
+
else
|
95
|
+
rule_description = ""
|
96
|
+
end
|
97
|
+
|
98
|
+
rule_xml += ">\n\t<Description>#{rule_description}</Description>\n\t<Source><![CDATA[\n#{rule['source']}\n]]></Source>\n</Rule>"
|
99
|
+
|
100
|
+
return rule_xml
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Exports Rule configurations.
|
105
|
+
#
|
106
|
+
def self.export( directory )
|
107
|
+
|
108
|
+
response = IDNAPI.get( "#{$url}/cc/api/rule/list", $token )
|
109
|
+
|
110
|
+
case response
|
111
|
+
when Net::HTTPSuccess
|
112
|
+
|
113
|
+
rules = JSON.parse( response.body )
|
114
|
+
|
115
|
+
$log.info "\tDetected #{rules["count"]} rules."
|
116
|
+
|
117
|
+
rules["items"].each do |rule|
|
118
|
+
|
119
|
+
if (!@@default_rules.include? rule["name"]) || $config["include-defaults"]
|
120
|
+
|
121
|
+
$log.info "\tRule: #{rule["name"]}"
|
122
|
+
|
123
|
+
if rule["type"].nil?
|
124
|
+
Program.write_file( "#{directory}/rules/", "Rule - Generic - #{rule["name"]}.xml", Rules.get_xml( rule ) )
|
125
|
+
else
|
126
|
+
Program.write_file( "#{directory}/rules/", "Rule - #{rule["type"]} - #{rule["name"]}.xml", Rules.get_xml( rule ) )
|
127
|
+
end
|
128
|
+
|
129
|
+
else
|
130
|
+
|
131
|
+
$log.info "\tSkipping Default Rule: #{rule["name"]}"
|
132
|
+
|
133
|
+
end # if (!@@default_transforms.include? transform["id"]...
|
134
|
+
|
135
|
+
end # rules["items"].each do |rule|
|
136
|
+
|
137
|
+
else
|
138
|
+
$log.error "\tError: Unable to fetch rules."
|
139
|
+
end # case response
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Imports Rule configurations.
|
145
|
+
#
|
146
|
+
def self.import( directory )
|
147
|
+
$log.warn "\t Import of rules is not supported. Please contact SailPoint in order to install a rule in the system."
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# Documents Rule configurations.
|
152
|
+
#
|
153
|
+
def self.doc
|
154
|
+
|
155
|
+
response = IDNAPI.get( "#{$url}/cc/api/rule/list", $token )
|
156
|
+
|
157
|
+
case response
|
158
|
+
when Net::HTTPSuccess
|
159
|
+
|
160
|
+
rules = JSON.parse( response.body )
|
161
|
+
|
162
|
+
$log.info "\tDetected #{rules["count"]} rules."
|
163
|
+
|
164
|
+
Markdown.h2 "Rules"
|
165
|
+
|
166
|
+
rules["items"].each do |rule|
|
167
|
+
|
168
|
+
if (!@@default_rules.include? rule["name"]) || $config["include-defaults"]
|
169
|
+
|
170
|
+
$log.info "\tRule: #{rule["name"]}"
|
171
|
+
|
172
|
+
if rule["type"].nil?
|
173
|
+
Markdown.h3 "#{rule["name"]} (Generic)"
|
174
|
+
else
|
175
|
+
Markdown.h3 "#{rule["name"]} (#{rule["type"]})"
|
176
|
+
end
|
177
|
+
|
178
|
+
unless rule['description'].nil?
|
179
|
+
Markdown.text "#{rule['description'].gsub(/\t+|\s+/," ").gsub(/(\r\n)+|\r+|^\s+|\s+$|\n+?/,"")}\n"
|
180
|
+
end
|
181
|
+
|
182
|
+
Markdown.xml Rules.get_xml( rule )
|
183
|
+
|
184
|
+
else
|
185
|
+
|
186
|
+
$log.info "\tSkipping Default Rule: #{rule["name"]}"
|
187
|
+
|
188
|
+
end # if (!@@default_transforms.include? transform["id"]...
|
189
|
+
|
190
|
+
end # rules["items"].each do |rule|
|
191
|
+
|
192
|
+
else
|
193
|
+
$log.error "\tError: Unable to fetch rules."
|
194
|
+
end # case response
|
195
|
+
|
196
|
+
Markdown.write
|
197
|
+
end
|
198
|
+
end
|