simple_crowd 1.0.5 → 1.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/Gemfile CHANGED
@@ -4,5 +4,12 @@ source "http://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  group :test do
7
+ gem 'factory_girl', '>= 2.0.1'
8
+ gem 'fcoury-matchy', '>= 0.4.0'
9
+ gem 'shoulda', '>= 2.0.0'
10
+ gem 'forgery', '>= 0.4.0'
11
+ gem 'webmock', '>= 1.8.0'
12
+ gem 'rr', '>= 1.0.0'
13
+
7
14
  gem 'i18n'
8
15
  end
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
- require 'rake/rdoctask'
3
+ require 'rdoc/task'
4
4
  require 'bundler'
5
5
  Bundler::GemHelper.install_tasks
6
6
 
@@ -0,0 +1,86 @@
1
+ module SimpleCrowd
2
+ module Cache
3
+
4
+ # A cache store implementation which doesn't actually store anything.
5
+ #
6
+ # Implements ActiveSupport::Cache::Store interface without depending on
7
+ # the active_support gem.
8
+ class NullStore
9
+ attr_reader :silence, :options
10
+ alias :silence? :silence
11
+
12
+ def initialize(options = nil)
13
+ end
14
+
15
+ def mute
16
+ yield
17
+ end
18
+
19
+ def silence!
20
+ end
21
+
22
+ def synchronize
23
+ yield
24
+ end
25
+
26
+ def fetch(name, options = nil)
27
+ if block_given?
28
+ yield
29
+ else
30
+ read(name, options)
31
+ end
32
+ end
33
+
34
+ def read(name, options = nil)
35
+ nil
36
+ end
37
+
38
+ def write(name, vaue, options = nil)
39
+ true
40
+ end
41
+
42
+ def delete(name, options = nil)
43
+ false
44
+ end
45
+
46
+ def exist?(name, options = nil)
47
+ false
48
+ end
49
+
50
+ def clear(options = nil)
51
+ end
52
+
53
+ def cleanup(options = nil)
54
+ end
55
+
56
+ def increment(name, amount = 1, options = nil)
57
+ end
58
+
59
+ def decrement(name, amount = 1, options = nil)
60
+ end
61
+
62
+ def delete_matched(matcher, options = nil)
63
+ end
64
+
65
+ def self.logger
66
+ nil
67
+ end
68
+
69
+ def self.logger=(logger)
70
+ end
71
+
72
+ protected
73
+
74
+ def read_entry(key, options) # :nodoc:
75
+ end
76
+
77
+ def write_entry(key, entry, options) # :nodoc:
78
+ true
79
+ end
80
+
81
+ def delete_entry(key, options) # :nodoc:
82
+ false
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,298 +1,334 @@
1
- module SimpleCrowd
2
- class Client
3
-
4
- attr_reader :options
5
-
6
- def initialize options = {}
7
- @options = SimpleCrowd.options options
8
-
9
- # TODO: Fix error handling
10
- # Errors do not contained Exception info so we'll handle the errors ourselves
11
- # Savon::Response.raise_errors = false
12
- # @client = Savon::Client.new @options[:service_url]
13
- yield(@options) if block_given?
14
- end
15
- def app_token
16
- @app_token ||= authenticate_application
17
- end
18
- attr_writer :app_token
19
-
20
- def get_cookie_info
21
- simple_soap_call :get_cookie_info
22
- end
23
-
24
- def get_granted_authorities
25
- groups = simple_soap_call :get_granted_authorities
26
- groups[:string] unless groups.nil?
27
- end
28
-
29
- def authenticate_application(name = @options[:app_name], password = @options[:app_password])
30
- response = client.authenticate_application! do |soap|
31
- prepare soap
32
- soap.body = {:in0 => {
33
- 'auth:name' => name,
34
- 'auth:credential' => {'auth:credential' => password}
35
- }.merge(no_validation_factors)}
36
- end
37
- raise CrowdError.new(response.soap_fault, response.to_hash[:fault]) if response.soap_fault?
38
- response.to_hash[:authenticate_application_response][:out][:token]
39
- end
40
-
41
- # Authenticate user by name/pass and retrieve login token
42
- # @return [String] user token
43
- def authenticate_user name, password, factors = nil
44
- if factors
45
- factors = prepare_validation_factors(factors)
46
- simple_soap_call :authenticate_principal, {'auth:application' => @options[:app_name], 'auth:name' => name,
47
- 'auth:credential' => {'auth:credential' => password},
48
- 'auth:validationFactors' => factors}
49
- else
50
- simple_soap_call :authenticate_principal_simple, name, password
51
- end
52
- end
53
-
54
- def create_user_token name
55
- simple_soap_call :create_principal_token, name, nil
56
- end
57
-
58
- # Invalidate an existing user token (log out)
59
- # NOTE: call will return true even if token is invalid
60
- # @return [Boolean] success (does not guarantee valid token)
61
- def invalidate_user_token token
62
- simple_soap_call :invalidate_principal_token, token do |res|
63
- !res.soap_fault? && res.to_hash.key?(:invalidate_principal_token_response)
64
- end
65
- end
66
-
67
- def is_valid_user_token? token, factors = nil
68
- factors = prepare_validation_factors(factors) unless factors.nil?
69
- simple_soap_call :is_valid_principal_token, token, factors
70
- end
71
-
72
- def is_cache_enabled?
73
- simple_soap_call :is_cache_enabled
74
- end
75
-
76
- def is_group_member? group, user
77
- simple_soap_call :is_group_member, group, user
78
- end
79
-
80
- def find_group_by_name name
81
- SimpleCrowd::Group.parse_from :soap, simple_soap_call(:find_group_by_name, name)
82
- end
83
-
84
- def find_all_group_names
85
- (simple_soap_call :find_all_group_names)[:string]
86
- end
87
-
88
- def update_group group, description, active
89
- simple_soap_call :update_group, group, description, active do |res|
90
- !res.soap_fault? && res.to_hash.key?(:update_group_response)
91
- end
92
- end
93
-
94
- def add_user_to_group user, group
95
- simple_soap_call :add_principal_to_group, user, group do |res|
96
- !res.soap_fault? && res.to_hash.key?(:add_principal_to_group_response)
97
- end
98
- end
99
-
100
- def remove_user_from_group user, group
101
- simple_soap_call :remove_principal_from_group, user, group do |res|
102
- !res.soap_fault? && res.to_hash.key?(:remove_principal_from_group_response)
103
- end
104
- end
105
-
106
- def reset_user_password name
107
- simple_soap_call :reset_principal_credential, name do |res|
108
- !res.soap_fault? && res.to_hash.key?(:reset_principal_credential_response)
109
- end
110
- end
111
-
112
- def find_all_user_names
113
- (simple_soap_call :find_all_principal_names)[:string]
114
- end
115
-
116
- def find_user_by_name name
117
- SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_by_name, name) rescue nil
118
- end
119
-
120
- def find_user_with_attributes_by_name name
121
- SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_with_attributes_by_name, name) rescue nil
122
- end
123
-
124
- def find_user_by_token token
125
- SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_by_token, token) rescue nil
126
- end
127
-
128
- def find_username_by_token token
129
- user = find_user_by_token token
130
- user && user[:username]
131
- end
132
-
133
- # Exact email match
134
- def find_user_by_email email
135
- search_users_by_email(email).find{|u| u.email.casecmp(email) == 0}
136
- end
137
-
138
- # Partial email match
139
- def search_users_by_email email
140
- search_users({'principal.email' => email})
141
- end
142
-
143
- def search_users restrictions
144
- soap_restrictions = prepare_search_restrictions restrictions
145
- users = simple_soap_call :search_principals, soap_restrictions rescue []
146
- return [] if users.nil? || users[:soap_principal].nil?
147
- users = users[:soap_principal].is_a?(Array) ? users[:soap_principal] : [users[:soap_principal]]
148
- users.map{|u| SimpleCrowd::User.parse_from :soap, u}
149
- end
150
-
151
- def add_user user, credential
152
- return if user.nil? || credential.nil?
153
- [:email, :first_name, :last_name].each do |k|
154
- user.send(:"#{k}=", "") if user.send(k).nil?
155
- end
156
- soap_user = user.map_to :soap
157
- # We don't use these attributes when creating
158
- soap_user.delete(:id)
159
- soap_user.delete(:directory_id)
160
- # Add blank attributes if missing
161
-
162
- # Declare require namespaces
163
- soap_user = soap_user.inject({}) {|hash, (k, v)| hash["int:#{k}"] = v;hash}
164
- SimpleCrowd::User.parse_from :soap, simple_soap_call(:add_principal, soap_user, {'auth:credential' => credential, 'auth:encryptedCredential' => false})
165
- end
166
-
167
- def remove_user name
168
- simple_soap_call :remove_principal, name do |res|
169
- !res.soap_fault? && res.to_hash.key?(:remove_principal_response)
170
- end
171
- end
172
-
173
- def update_user_credential user, credential, encrypted = false
174
- simple_soap_call :update_principal_credential, user,
175
- {'auth:credential' => credential, 'auth:encryptedCredential' => encrypted} do |res|
176
- !res.soap_fault? && res.to_hash.key?(:update_principal_credential_response)
177
- end
178
- end
179
-
180
- # Only supports single value attributes
181
- # TODO: Allow value arrays
182
- # @param user [String] name of user to update
183
- # @param name [String] of attribute to update
184
- # @param value [String] of attribute to update
185
- def update_user_attribute user, name, value
186
- return unless (name.is_a?(String) || name.is_a?(Symbol)) && (value.is_a?(String) || value.is_a?(Array))
187
- soap_attr = SimpleCrowd::Mappers::SoapAttributes.produce({name => value})
188
- simple_soap_call :update_principal_attribute, user, soap_attr['int:SOAPAttribute'][0] do |res|
189
- !res.soap_fault? && res.to_hash.key?(:update_principal_attribute_response)
190
- end
191
- end
192
- alias_method :add_user_attribute, :update_user_attribute
193
-
194
- # @param user [SimpleCrowd::User] dirty user to update
195
- def update_user user
196
- return unless user.dirty?
197
- # Exclude non-attribute properties (only attributes can be updated in crowd)
198
- attrs_to_update = user.dirty_attributes
199
- return if attrs_to_update.empty?
200
-
201
- attrs_to_update.each do |a|
202
- prop = SimpleCrowd::User.property_by_name a
203
- soap_prop = prop.maps[:soap].nil? ? prop : prop.maps[:soap]
204
- self.update_user_attribute user.username, soap_prop, user.send(a)
205
- end
206
- end
207
-
208
- private
209
-
210
- # Simplify the duplicated soap calls across methods
211
- # @param [Symbol] action the soap action to call
212
- # @param data the list of args to pass to the server as "in" args (in1, in2, etc.)
213
- def simple_soap_call action, *data
214
- # Take each arg and assign it to "in" keys for SOAP call starting with in1 (in0 is app token)
215
- soap_args = data.inject({}){|hash, arg| hash[:"in#{hash.length + 1}"] = arg; hash }
216
- # Ordered "in" keys ex. in1, in2, etc. for SOAP ordering
217
- in_keys = soap_args.length ? (1..soap_args.length).collect {|v| :"in#{v}" } : []
218
- # Make the SOAP call to the dynamic action
219
- response = with_app_token do
220
- client.send :"#{action}!" do |soap|
221
- prepare soap
222
- # Pass in all the args as "in" vars
223
- soap.body = {:in0 => hash_authenticated_token}.merge(soap_args).merge({:order! => [:in0, *in_keys]})
224
- end
225
- end
226
- # If a block is given then call it and pass in the response object, otherwise get the default out value
227
- block_given? ? yield(response) : response.to_hash[:"#{action}_response"][:out]
228
- end
229
-
230
- def with_app_token retries = 1, &block
231
- begin
232
- Savon::Response.raise_errors = false
233
- response = block.call
234
- raise CrowdError.new(response.soap_fault, response.to_hash[:fault]) if response.soap_fault?
235
- return response
236
- rescue CrowdError => e
237
- if retries > 0 && e.type?(:invalid_authorization_token_exception)
238
- # Clear token to force a refresh
239
- self.app_token = nil
240
- retries -= 1
241
- retry
242
- end
243
- raise
244
- ensure
245
- Savon::Response.raise_errors = true
246
- end
247
- end
248
-
249
- # Generate new client on every request (Savon bug?)
250
- def client
251
- Savon::Client.new @options[:service_url]
252
- end
253
-
254
- # Setup soap object for request
255
- def prepare soap
256
- soap.namespace = @options[:service_ns]
257
- soap.namespaces.merge! @options[:service_namespaces]
258
- end
259
-
260
- # Take Crowd SOAP attribute format and return a simple ruby hash
261
- # @param attributes the soap attributes array
262
- def process_soap_attributes attributes
263
- soap = attributes[:soap_attribute]
264
- (soap && soap.inject({}) {|hash, attr| hash[attr[:name].to_sym] = attr[:values][:string]; hash }) || {}
265
- end
266
-
267
- def map_group_hash group
268
- attributes = process_soap_attributes group[:attributes]
269
- supported_keys = attributes.keys & SimpleCrowd::Group.mapped_properties(:soap)
270
- group = group.merge attributes.inject({}) {|map, (k, v)| map[k] = v if supported_keys.include? k; map}
271
- group[:attributes] = attributes.inject({}) {|map, (k, v)| map[k] = v unless supported_keys.include? k; map}
272
- group.delete :attributes if group[:attributes].empty?
273
- SimpleCrowd::Group.new group
274
- end
275
-
276
- def prepare_validation_factors factors
277
- {'auth:validationFactor' =>
278
- factors.inject([]) {|arr, factor| arr << {'auth:name' => factor[0], 'auth:value' => factor[1]} }
279
- }
280
- end
281
-
282
- def prepare_search_restrictions restrictions
283
- {'int:searchRestriction' =>
284
- restrictions.inject([]) {|arr, restrict| arr << {'int:name' => restrict[0], 'int:value' => restrict[1]}}
285
- }
286
- end
287
-
288
- def hash_authenticated_token name = @options[:app_name], token = nil
289
- token ||= app_token
290
- {'auth:name' => name, 'auth:token' => token}
291
- end
292
-
293
- def no_validation_factors
294
- {'auth:validationFactors' => {}, :attributes! => {'auth:validationFactors' => {'xsi:nil' => true}}}
295
- end
296
-
297
- end
298
- end
1
+ module SimpleCrowd
2
+ class Client
3
+
4
+ attr_reader :options
5
+ attr_accessor :app_token, :cache_store
6
+
7
+ def initialize options = {}
8
+ @options = SimpleCrowd.options options
9
+ yield(@options) if block_given?
10
+ self.cache_store = @options.delete(:cache_store)
11
+ end
12
+
13
+ def get_cookie_info
14
+ @cookie_info ||= cache.fetch(cache_key(:cookie_info)) do
15
+ # Remove custom SOAP attributes from the strings
16
+ simple_soap_call(:get_cookie_info).inject({}) do |cookie_info, (key, val)|
17
+ cookie_info[key] = val ? val.to_s : val
18
+ cookie_info
19
+ end
20
+ end
21
+ end
22
+
23
+ def get_granted_authorities
24
+ groups = simple_soap_call :get_granted_authorities
25
+ groups[:string] unless groups.nil?
26
+ end
27
+
28
+ def authenticate_application(name = @options[:app_name], password = @options[:app_password])
29
+ response = convert_soap_errors do
30
+ client.request :authenticate_application do |soap|
31
+ prepare soap
32
+ soap.body = {:in0 => {
33
+ 'auth:name' => name,
34
+ 'auth:credential' => {'auth:credential' => password}
35
+ }.merge(no_validation_factors)}
36
+ end
37
+ end
38
+ response.to_hash[:authenticate_application_response][:out][:token].to_s
39
+ end
40
+
41
+ # Authenticate user by name/pass and retrieve login token
42
+ # @return [String] user token
43
+ def authenticate_user name, password, factors = nil
44
+ if factors
45
+ factors = prepare_validation_factors(factors)
46
+ simple_soap_call :authenticate_principal, {'auth:application' => @options[:app_name], 'auth:name' => name,
47
+ 'auth:credential' => {'auth:credential' => password},
48
+ 'auth:validationFactors' => factors}
49
+ else
50
+ simple_soap_call :authenticate_principal_simple, name, password
51
+ end
52
+ end
53
+
54
+ def create_user_token name
55
+ simple_soap_call :create_principal_token, name, nil
56
+ end
57
+
58
+ # Invalidate an existing user token (log out)
59
+ # NOTE: call will return true even if token is invalid
60
+ # @return [Boolean] success (does not guarantee valid token)
61
+ def invalidate_user_token token
62
+ simple_soap_call :invalidate_principal_token, token do |res|
63
+ !res.soap_fault? && res.to_hash.key?(:invalidate_principal_token_response)
64
+ end
65
+ end
66
+
67
+ def is_valid_user_token? token, factors = nil
68
+ factors = prepare_validation_factors(factors)
69
+ simple_soap_call :is_valid_principal_token, token, factors
70
+ end
71
+
72
+ def is_cache_enabled?
73
+ simple_soap_call :is_cache_enabled
74
+ end
75
+
76
+ def is_group_member? group, user
77
+ simple_soap_call :is_group_member, group, user
78
+ end
79
+
80
+ def find_group_by_name name
81
+ SimpleCrowd::Group.parse_from :soap, simple_soap_call(:find_group_by_name, name)
82
+ end
83
+
84
+ def find_all_group_names
85
+ (simple_soap_call :find_all_group_names)[:string]
86
+ end
87
+
88
+ def update_group group, description, active
89
+ simple_soap_call :update_group, group, description, active do |res|
90
+ !res.soap_fault? && res.to_hash.key?(:update_group_response)
91
+ end
92
+ end
93
+
94
+ def add_user_to_group user, group
95
+ simple_soap_call :add_principal_to_group, user, group do |res|
96
+ !res.soap_fault? && res.to_hash.key?(:add_principal_to_group_response)
97
+ end
98
+ end
99
+
100
+ def remove_user_from_group user, group
101
+ simple_soap_call :remove_principal_from_group, user, group do |res|
102
+ !res.soap_fault? && res.to_hash.key?(:remove_principal_from_group_response)
103
+ end
104
+ end
105
+
106
+ def reset_user_password name
107
+ simple_soap_call :reset_principal_credential, name do |res|
108
+ !res.soap_fault? && res.to_hash.key?(:reset_principal_credential_response)
109
+ end
110
+ end
111
+
112
+ def find_all_user_names
113
+ (simple_soap_call :find_all_principal_names)[:string]
114
+ end
115
+
116
+ def find_user_by_name name
117
+ SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_by_name, name) rescue nil
118
+ end
119
+
120
+ def find_user_with_attributes_by_name name
121
+ SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_with_attributes_by_name, name) rescue nil
122
+ end
123
+
124
+ def find_user_by_token token
125
+ SimpleCrowd::User.parse_from :soap, simple_soap_call(:find_principal_by_token, token) rescue nil
126
+ end
127
+
128
+ def find_username_by_token token
129
+ user = find_user_by_token token
130
+ user && user[:username]
131
+ end
132
+
133
+ # Exact email match
134
+ def find_user_by_email email
135
+ search_users_by_email(email).find{|u| u.email == email}
136
+ end
137
+
138
+ # Partial email match
139
+ def search_users_by_email email
140
+ search_users({'principal.email' => email})
141
+ end
142
+
143
+ def search_users restrictions
144
+ soap_restrictions = prepare_search_restrictions restrictions
145
+ users = simple_soap_call :search_principals, soap_restrictions rescue []
146
+ return [] if users.nil? || users[:soap_principal].nil?
147
+ users = users[:soap_principal].is_a?(Array) ? users[:soap_principal] : [users[:soap_principal]]
148
+ users.map{|u| SimpleCrowd::User.parse_from :soap, u}
149
+ end
150
+
151
+ def add_user user, credential
152
+ return if user.nil? || credential.nil?
153
+ [:email, :first_name, :last_name].each do |k|
154
+ user.send(:"#{k}=", "") if user.send(k).nil?
155
+ end
156
+ soap_user = user.map_to :soap
157
+ # We don't use these attributes when creating
158
+ soap_user.delete(:id)
159
+ soap_user.delete(:directory_id)
160
+ # Add blank attributes if missing
161
+
162
+ # Declare require namespaces
163
+ soap_user = soap_user.inject({}) {|hash, (k, v)| hash["int:#{k}"] = v;hash}
164
+ SimpleCrowd::User.parse_from :soap, simple_soap_call(:add_principal, soap_user, {'auth:credential' => credential, 'auth:encryptedCredential' => false})
165
+ end
166
+
167
+ def remove_user name
168
+ simple_soap_call :remove_principal, name do |res|
169
+ !res.soap_fault? && res.to_hash.key?(:remove_principal_response)
170
+ end
171
+ end
172
+
173
+ def update_user_credential user, credential, encrypted = false
174
+ simple_soap_call :update_principal_credential, user,
175
+ {'auth:credential' => credential, 'auth:encryptedCredential' => encrypted} do |res|
176
+ !res.soap_fault? && res.to_hash.key?(:update_principal_credential_response)
177
+ end
178
+ end
179
+
180
+ # Only supports single value attributes
181
+ # TODO: Allow value arrays
182
+ # @param user [String] name of user to update
183
+ # @param name [String] of attribute to update
184
+ # @param value [String] of attribute to update
185
+ def update_user_attribute user, name, value
186
+ return unless (name.is_a?(String) || name.is_a?(Symbol)) && (value.is_a?(String) || value.is_a?(Array))
187
+ soap_attr = SimpleCrowd::Mappers::SoapAttributes.produce({name => value})
188
+ simple_soap_call :update_principal_attribute, user, soap_attr['int:SOAPAttribute'][0] do |res|
189
+ !res.soap_fault? && res.to_hash.key?(:update_principal_attribute_response)
190
+ end
191
+ end
192
+ alias_method :add_user_attribute, :update_user_attribute
193
+
194
+ # @param user [SimpleCrowd::User] dirty user to update
195
+ def update_user user
196
+ return unless user.dirty?
197
+ # Exclude non-attribute properties (only attributes can be updated in crowd)
198
+ attrs_to_update = user.dirty_attributes
199
+ return if attrs_to_update.empty?
200
+
201
+ attrs_to_update.each do |a|
202
+ prop = SimpleCrowd::User.property_by_name a
203
+ soap_prop = prop.maps[:soap].nil? ? prop : prop.maps[:soap]
204
+ self.update_user_attribute user.username, soap_prop, user.send(a)
205
+ end
206
+ end
207
+
208
+ def app_token
209
+ @app_token ||= cache.read(cache_key(:app_token))
210
+ end
211
+
212
+ def app_token=(token)
213
+ cache.write(cache_key(:app_token), token)
214
+ @app_token = token
215
+ end
216
+
217
+ def cache_store=(store)
218
+ @cache_store = store || Cache::NullStore.new
219
+ end
220
+ alias_method :cache, :cache_store
221
+
222
+ def reset_cache
223
+ [:app_token, :cookie_info].each do |key|
224
+ cache.delete(cache_key(key))
225
+ end
226
+ end
227
+
228
+ private
229
+
230
+ # Simplify the duplicated soap calls across methods
231
+ # @param [Symbol] action the soap action to call
232
+ # @param data the list of args to pass to the server as "in" args (in1, in2, etc.)
233
+ def simple_soap_call action, *data
234
+ # Take each arg and assign it to "in" keys for SOAP call starting with in1 (in0 is app token)
235
+ soap_args = data.inject({}){|hash, arg| hash[:"in#{hash.length + 1}"] = arg; hash }
236
+ # Ordered "in" keys ex. in1, in2, etc. for SOAP ordering
237
+ in_keys = soap_args.length ? (1..soap_args.length).collect {|v| :"in#{v}" } : []
238
+ # Make the SOAP call to the dynamic action
239
+ response = client_with_app_token do |client|
240
+ convert_soap_errors do
241
+ client.request :"#{action}" do |soap|
242
+ prepare soap
243
+ # Pass in all the args as "in" vars
244
+ soap.body = {:in0 => hash_authenticated_token}.merge(soap_args).merge({:order! => [:in0, *in_keys]})
245
+ end
246
+ end
247
+ end
248
+ # If a block is given then call it and pass in the response object, otherwise get the default out value
249
+ block_given? ? yield(response) : response.to_hash[:"#{action}_response"][:out]
250
+ end
251
+
252
+ def convert_soap_errors
253
+ begin
254
+ old_raise_errors = Savon.raise_errors?
255
+ Savon.raise_errors = true
256
+ yield
257
+ rescue Savon::SOAP::Fault => fault
258
+ raise CrowdError.new(fault.to_s, fault)
259
+ rescue Savon::HTTP::Error => e
260
+ raise CrowdError.new(e.to_s)
261
+ ensure
262
+ Savon.raise_errors = old_raise_errors
263
+ end
264
+ end
265
+
266
+ def client
267
+ @client ||= Savon::Client.new do
268
+ wsdl.endpoint = options[:service_url]
269
+ wsdl.namespace = options[:service_ns]
270
+ end
271
+ end
272
+
273
+ def client_with_app_token retries = 1
274
+ self.app_token = authenticate_application unless self.app_token
275
+ begin
276
+ yield client
277
+ rescue CrowdError => e
278
+ if retries > 0 && e.type?(:invalid_authorization_token_exception)
279
+ # Refresh the app token
280
+ self.app_token = authenticate_application
281
+ retries -= 1
282
+ retry
283
+ end
284
+ raise
285
+ end
286
+ end
287
+
288
+ # Setup soap object for request
289
+ def prepare soap
290
+ soap.namespaces.merge! options[:service_namespaces]
291
+ end
292
+
293
+ # Take Crowd SOAP attribute format and return a simple ruby hash
294
+ # @param attributes the soap attributes array
295
+ def process_soap_attributes attributes
296
+ soap = attributes[:soap_attribute]
297
+ (soap && soap.inject({}) {|hash, attr| hash[attr[:name].to_sym] = attr[:values][:string]; hash }) || {}
298
+ end
299
+
300
+ def map_group_hash group
301
+ attributes = process_soap_attributes group[:attributes]
302
+ supported_keys = attributes.keys & SimpleCrowd::Group.mapped_properties(:soap)
303
+ group = group.merge attributes.inject({}) {|map, (k, v)| map[k] = v if supported_keys.include? k; map}
304
+ group[:attributes] = attributes.inject({}) {|map, (k, v)| map[k] = v unless supported_keys.include? k; map}
305
+ group.delete :attributes if group[:attributes].empty?
306
+ SimpleCrowd::Group.new group
307
+ end
308
+
309
+ def prepare_validation_factors factors
310
+ {'auth:validationFactor' =>
311
+ (factors || []).inject([]) {|arr, factor| arr << {'auth:name' => factor[0], 'auth:value' => factor[1]} }
312
+ }
313
+ end
314
+
315
+ def prepare_search_restrictions restrictions
316
+ {'int:searchRestriction' =>
317
+ restrictions.inject([]) {|arr, restrict| arr << {'int:name' => restrict[0], 'int:value' => restrict[1]}}
318
+ }
319
+ end
320
+
321
+ def hash_authenticated_token name = @options[:app_name], token = nil
322
+ token ||= app_token
323
+ {'auth:name' => name, 'auth:token' => token}
324
+ end
325
+
326
+ def no_validation_factors
327
+ {'auth:validationFactors' => {}, :attributes! => {'auth:validationFactors' => {'xsi:nil' => true}}}
328
+ end
329
+
330
+ def cache_key(key)
331
+ "#{@options[:cache_prefix]}#{key}"
332
+ end
333
+ end
334
+ end