soteria 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +77 -0
  9. data/Rakefile +5 -0
  10. data/bin/bundler +17 -0
  11. data/bin/console +17 -0
  12. data/bin/htmldiff +17 -0
  13. data/bin/ldiff +17 -0
  14. data/bin/nokogiri +17 -0
  15. data/bin/rackup +17 -0
  16. data/bin/rake +17 -0
  17. data/bin/rspec +17 -0
  18. data/bin/setup +17 -0
  19. data/bin/socksify_ruby +17 -0
  20. data/lib/soteria.rb +10 -0
  21. data/lib/soteria/client.rb +326 -0
  22. data/lib/soteria/credential.rb +154 -0
  23. data/lib/soteria/credential_types.rb +13 -0
  24. data/lib/soteria/push.rb +141 -0
  25. data/lib/soteria/sms.rb +81 -0
  26. data/lib/soteria/user.rb +409 -0
  27. data/lib/soteria/utilities.rb +45 -0
  28. data/lib/soteria/version.rb +4 -0
  29. data/soteria.gemspec +26 -0
  30. data/spec/credential_spec.rb +121 -0
  31. data/spec/fixtures/credential/authenticate_credentials_response.xml +13 -0
  32. data/spec/fixtures/credential/credential_fail.xml +11 -0
  33. data/spec/fixtures/credential/credential_success.xml +12 -0
  34. data/spec/fixtures/credential/get_cred_info_response.xml +40 -0
  35. data/spec/fixtures/credential/get_server_time_response.xml +11 -0
  36. data/spec/fixtures/credential/register_sms_response.xml +12 -0
  37. data/spec/fixtures/push/authenticate_with_push_error.xml +9 -0
  38. data/spec/fixtures/push/authenticate_with_push_response.xml +14 -0
  39. data/spec/fixtures/sms/check_otp_success_response.xml +13 -0
  40. data/spec/fixtures/sms/send_sms_success_response.xml +10 -0
  41. data/spec/fixtures/user/add_credential_response.xml +9 -0
  42. data/spec/fixtures/user/clear_temp_password_response.xml +10 -0
  43. data/spec/fixtures/user/clear_user_pin_response.xml +10 -0
  44. data/spec/fixtures/user/create_user_response.xml +9 -0
  45. data/spec/fixtures/user/delete_user_response.xml +10 -0
  46. data/spec/fixtures/user/get_temp_pass_attr_response.xml +14 -0
  47. data/spec/fixtures/user/remove_credential_response.xml +10 -0
  48. data/spec/fixtures/user/set_temp_pass_attr_response.xml +10 -0
  49. data/spec/fixtures/user/set_temp_pass_response.xml +11 -0
  50. data/spec/fixtures/user/update_credential_response.xml +10 -0
  51. data/spec/fixtures/user/update_user_response.xml +10 -0
  52. data/spec/fixtures/wsdl/vipuserservices-1.7.xsd +1015 -0
  53. data/spec/fixtures/wsdl/vipuserservices-auth-1.7.wsdl +155 -0
  54. data/spec/fixtures/wsdl/vipuserservices-mgmt-1.7.wsdl +246 -0
  55. data/spec/fixtures/wsdl/vipuserservices-query-1.7.wsdl +114 -0
  56. data/spec/push_spec.rb +148 -0
  57. data/spec/sms_spec.rb +84 -0
  58. data/spec/soteria_spec.rb +8 -0
  59. data/spec/spec_helper.rb +2 -0
  60. data/spec/user_spec.rb +245 -0
  61. metadata +206 -0
@@ -0,0 +1,154 @@
1
+ module Soteria
2
+
3
+ class Credential
4
+
5
+
6
+ def get_return_hash(response_hash)
7
+ success = response_hash[:status] == '0000'
8
+
9
+ {
10
+ success: success,
11
+ message: response_hash[:status_message],
12
+ id: response_hash[:request_id],
13
+ auth_id: response_hash[:authn_id],
14
+ detail: response_hash[:detail_message]
15
+ }
16
+ end
17
+
18
+
19
+ # Authenticate a user with a credential. A credential includes a physical token, the desktop VIP credential app or
20
+ # the mobile VIP credential app. Users must link their credential id to their user id for this authentication to work.
21
+ #
22
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP authentication WSDL.
23
+ # @param [String] user_id Id of the user to authenticate. This is the user id that is stored in the Symantec db.
24
+ # @param [String] credential_code The code from the users credential that was entered into the website.
25
+ # @return [Hash] A hash with information on if the authentication was successful.
26
+ def authenticate_user_credential(client, user_id, credential_code)
27
+ result = client.call(:authenticate_user,
28
+ message: {
29
+ 'vip:requestId': Utilities.get_request_id('authenticate_user_credential'),
30
+ 'vip:userId': user_id,
31
+ 'vip:otpAuthData':
32
+ {
33
+ 'vip:otp': credential_code
34
+ }
35
+ })
36
+
37
+ get_return_hash(result.body[:authenticate_user_response])
38
+
39
+ end
40
+
41
+
42
+ # Create the body for the authenticate credentials request.
43
+ #
44
+ # @param [Integer] otp The One Time Password to check if valid.
45
+ # @param [Array] credentials An array of hashes, with between 1 and 5 credentials. Each hash should contain 2 values :id - the id of the credential and :type - the type of the credential.
46
+ # @return [Hash] A hash representing the request body for the authenticate credentials request.
47
+ def get_auth_body(otp, credentials)
48
+
49
+ credential_array = []
50
+
51
+ credentials.each do |credential|
52
+ credential_array.push({'vip:credentialId': credential[:id], 'vip:credentialType': credential[:type]})
53
+ end
54
+
55
+ {
56
+ 'vip:requestId': Utilities.get_request_id('authenticate_credentials'),
57
+ 'vip:credentials': credential_array,
58
+ 'vip:otpAuthData': {
59
+ 'vip:otp': otp
60
+ }
61
+ }
62
+
63
+ end
64
+
65
+
66
+ # Check if a otp is valid for a given credential.
67
+ #
68
+ # @param [Integer] otp The One Time Password to check if valid.
69
+ # @param [Array] credentials An array of hashes, with between 1 and 5 credentials. Each hash should contain 2 values :id - the id of the credential and :type - the type of the credential.
70
+ # @see CredentialTypes
71
+ # @return [Hash] A hash with all information about if the otp was successful
72
+ def authenticate_credentials(client, otp, credentials)
73
+ result = client.call(:authenticate_credentials, message: get_auth_body(otp, credentials))
74
+ get_return_hash(result.body[:authenticate_credentials_response])
75
+ end
76
+
77
+
78
+ # Register a SMS credential to the VIP Account. This must be done before you can add a SMS credential to a user.
79
+ #
80
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
81
+ # @param [Object] phone_number The phone number to register.
82
+ def register_sms(client, phone_number)
83
+ result = client.call(:register, message: {
84
+ 'vip:requestId': Utilities.get_request_id('register_credential'),
85
+ 'vip:smsDeliveryInfo': {
86
+ 'vip:phoneNumber': phone_number
87
+ }
88
+ } )
89
+
90
+ get_return_hash(result.body[:register_response])
91
+ end
92
+
93
+
94
+ # Use getCredentialInfo to get the credential that was last bound to the user, When the credential was last authenticated and
95
+ # the friendly name for the credential.
96
+ #
97
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP query WSDL.
98
+ # @param [String] credential_id The unique ID for the credential.
99
+ # @param [String] credential_type The type of the credential.
100
+ # @param [Boolean] include_push If this flag is present and set to be true, the response contains all the push attributes in the field pushAttributes.
101
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes. Also contains :credential which is a hash with info about the credential.
102
+ def get_credential_info(client, credential_id, credential_type, include_push)
103
+ message = {
104
+ 'vip:requestId': Utilities.get_request_id('get_credential_info'),
105
+ 'vip:credentialId': credential_id,
106
+ 'vip:credentialType': credential_type
107
+ }
108
+
109
+ unless include_push == nil
110
+ message[:'vip:includePushAttributes'] = include_push
111
+ end
112
+
113
+ response = client.call(:get_credential_info, message: message)
114
+ response_hash = response.body[:get_credential_info_response]
115
+
116
+ ret = get_return_hash(response_hash)
117
+
118
+ # get the credential info
119
+ credential = {
120
+ id: response_hash[:credential_id],
121
+ type: response_hash[:credential_type],
122
+ enabled: response_hash[:credential_status] == 'ENABLED'
123
+ }
124
+
125
+ # add the bindings if they exist
126
+ unless response_hash[:num_bindings] == '0'
127
+ credential[:user_binding] = response_hash[:user_binding_detail]
128
+ end
129
+
130
+ ret[:credential] = credential
131
+
132
+ ret
133
+ end
134
+
135
+
136
+ # Use getServerTime to obtain the current server time.
137
+ #
138
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP query WSDL.
139
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes. Also contains :time which is current server time.
140
+ def get_server_time(client)
141
+ response = client.call(:get_server_time, message: {'vip:requestId': Utilities.get_request_id('get_server_time')})
142
+ response_body = response.body[:get_server_time_response]
143
+ ret = get_return_hash(response_body)
144
+
145
+ unless response_body[:timestamp] == nil
146
+ ret[:time] = response_body[:timestamp]
147
+ end
148
+
149
+ ret
150
+ end
151
+
152
+ end
153
+
154
+ end
@@ -0,0 +1,13 @@
1
+ module Soteria
2
+
3
+ class CredentialTypes
4
+
5
+ STANDARD = 'STANDARD_OTP'
6
+ CERTIFICATE = 'CERTIFICATE'
7
+ SMS = 'SMS_OTP'
8
+ VOICE = 'VOICE_OTP'
9
+ SERVICE = 'SERVICE_OTP'
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,141 @@
1
+ require_relative 'utilities'
2
+ module Soteria
3
+
4
+ class Push
5
+
6
+
7
+ # Creates the body for a send push request.
8
+ #
9
+ # @param [String] user_id The id of the user to send the push to
10
+ # @param [Hash] options
11
+ # @return [Hash] A hash representing the body of the soap request to send a push notification.
12
+ def get_push_request_body(user_id, options)
13
+
14
+ # add in required values
15
+ message = {
16
+ 'vip:requestId': Utilities.get_request_id('send_push_request'),
17
+ 'vip:userId': user_id,
18
+ }
19
+
20
+ # no extra options so set the push auth data to nothing
21
+ # and return the body
22
+ if options == nil
23
+ message[:'vip:pushAuthData'] = ''
24
+ return message
25
+ end
26
+
27
+ #check if the user passed a pin, if so add it
28
+ if options.key?(:pin)
29
+ message[:'vip:pin'] = options[:pin]
30
+ end
31
+
32
+ # check for all push auth data options and add them
33
+ if options.key?(:title) || options.key?(:message) || options.key?(:profile) || options.key?(:time_out)
34
+ inner = []
35
+ if options.key?(:title)
36
+ inner.push({'vip:Key': 'display.message.title', 'vip:Value': options[:title]})
37
+ end
38
+ if options.key?(:message)
39
+ inner.push({'vip:Key': 'display.message.text', 'vip:Value': options[:message]})
40
+ end
41
+ if options.key?(:profile)
42
+ inner.push({'vip:Key': 'display.message.profile', 'vip:Value': options[:profile]})
43
+ end
44
+
45
+ # Add the options to the push auth data
46
+ if options.key?(:time_out)
47
+ message[:'vip:pushAuthData'] = {
48
+ 'vip:displayParameters': inner,
49
+ 'vip:requestParameters':
50
+ {
51
+ 'vip:Key': 'request.timeout',
52
+ 'vip:Value': options[:time_out]
53
+ }
54
+ }
55
+
56
+ else
57
+ message[:'vip:pushAuthData'] = {'vip:displayParameters': inner}
58
+ end
59
+
60
+ else
61
+ # dont add any push auth data
62
+ message[:'vip:pushAuthData'] = ''
63
+ end
64
+
65
+ # if options.key?(:level)
66
+ # message['authContext'] = {'params': {'Key': 'authLevel.level', 'Value': options[:level]}}
67
+ # end
68
+
69
+ message
70
+ end
71
+
72
+
73
+ # Send a push notification to the specified user for authentication.
74
+ #
75
+ # @param [Savon::Client] client A Savon client object to make the call with.
76
+ # @see Savon::Client
77
+ # @param [String] user_id The id of the user to send the push to
78
+ # @param [Hash] options
79
+ def send_push(client, user_id, options)
80
+
81
+ # get the body of the request
82
+ request_body = get_push_request_body(user_id, options)
83
+ push_res = client.call(:authenticate_user_with_push, message: request_body)
84
+ result_hash = push_res.body[:authenticate_user_with_push_response]
85
+
86
+ # 6040 is the status code for a push being sent, any other code the push was not sent
87
+ success = result_hash[:status] == '6040'
88
+
89
+ {
90
+ success: success,
91
+ id: result_hash[:request_id],
92
+ transaction_id: result_hash[:transaction_id],
93
+ message: result_hash[:status_message]
94
+ }
95
+
96
+ end
97
+
98
+
99
+ # Polls for the status of the push notification. This is necessary because VIP does not have push support.
100
+ # This will poll until the response is no longer push in progress, then it will return a hash with the results.
101
+ #
102
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP query WSDL.
103
+ # @param [String] transaction_id The id of the push transaction. id is in the hash returned from the send_push call
104
+ # @param [Int] interval An integer value in seconds that is the interval between polling VIP Services for a push response.
105
+ # @param [Int] time_out An integer value in seconds that is the timeout for polling. This should match the timeout that was set for the push message.
106
+ # @return [Hash] A hash with information on if the authentication was successful.
107
+ def poll_for_response(client, transaction_id, interval, time_out)
108
+
109
+ 1.upto(time_out/interval) do
110
+
111
+ response = client.call(:poll_push_status,
112
+ message: {
113
+ 'vip:requestId': Utilities.get_request_id("poll_push_status"),
114
+ 'vip:transactionId': transaction_id
115
+ })
116
+
117
+ # The status of the push is called transaciton status
118
+ transaction_status = response.body[:poll_push_status_response][:transaction_status]
119
+ call_status = response.body[:poll_push_status_response]
120
+
121
+ # 7001 is in progress so we are waiting for that to change
122
+ if transaction_status[:status] != '7001'
123
+
124
+ success = transaction_status[:status] == '7000'
125
+ return {
126
+ success: success,
127
+ message: transaction_status[:status_message],
128
+ id: call_status[:request_id]
129
+ }
130
+
131
+ end
132
+
133
+ sleep interval
134
+
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
141
+ end
@@ -0,0 +1,81 @@
1
+ module Soteria
2
+
3
+ class SMS
4
+
5
+
6
+ # Creates the body for a send SMS otp request.
7
+ #
8
+ # @param [String] user_id Id of the user to authenticate. This is the user id that is stored in the Symantec database.
9
+ # @param [Int] phone_number The phone number that the sms code should be sent to.
10
+ # @return [Hash] A hash with all information about if the otp was successful.
11
+ def create_send_sms_body(user_id, phone_number)
12
+ {
13
+ 'vip:requestId': Utilities.get_request_id('send_sms_otp'),
14
+ 'vip:userId': user_id,
15
+ 'vip:smsDeliveryInfo':
16
+ {
17
+ 'vip:phoneNumber': phone_number
18
+ }
19
+ }
20
+ end
21
+
22
+
23
+ # Send a sms One Time Password to a user.
24
+ #
25
+ # @param [String] user_id Id of the user to authenticate. This is the user id that is stored in the Symantec database.
26
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
27
+ # @param [Int] phone_number The phone number that the sms code should be sent to.
28
+ # @return [Hash] A hash with all the appropriate information about the status of the SMS.
29
+ def send_sms(client, user_id, phone_number)
30
+ sms_res = client.call(:send_otp, message: create_send_sms_body(user_id, phone_number))
31
+ result_hash = sms_res.body[:send_otp_response]
32
+ success = result_hash[:status] == '0000'
33
+
34
+ {
35
+ success: success,
36
+ id: result_hash[:request_id],
37
+ message: result_hash[:status_message]
38
+ }
39
+ end
40
+
41
+
42
+ # Creates the body for a check otp request.
43
+ #
44
+ # @param [String] user_id Id of the user to authenticate. This is the user id that is stored in the Symantec db.
45
+ # @param [Object] otp The otp that was sent to the user via sms or voice
46
+ # @return [Hash] A hash representing the body of the soap request to check if an otp is valid.
47
+ def create_check_otp_body(user_id, otp)
48
+ {
49
+ 'vip:requestId': Utilities.get_request_id('check_sms_otp'),
50
+ 'vip:userId': user_id,
51
+ 'vip:otpAuthData':
52
+ {
53
+ 'vip:otp': otp
54
+ }
55
+ }
56
+ end
57
+
58
+
59
+ # Check if the otp that a user entered is valid or not.
60
+ #
61
+ # @param [String] user_id Id of the user to authenticate. This is the user id that is stored in the Symantec db.
62
+ # @param [Object] otp The otp that was sent to the user via sms or voice
63
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP authentication WSDL.
64
+ # @return [Hash] A hash with all information about if the otp was successful
65
+ def check_otp(client, user_id, otp)
66
+ check_otp_response = client.call(:check_otp, message: create_check_otp_body(user_id, otp))
67
+ result_hash = check_otp_response.body[:check_otp_response]
68
+
69
+ success = result_hash[:status] == '0000'
70
+
71
+ {
72
+ success: success,
73
+ id: result_hash[:request_id],
74
+ message: result_hash[:status_message]
75
+ }
76
+ end
77
+
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,409 @@
1
+ module Soteria
2
+
3
+ class User
4
+
5
+
6
+ # Add a new user to the list of users in Symantec VIP database.
7
+ #
8
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
9
+ # @param [String] user_id Id of the user to create.
10
+ # @param [String] pin an optional value that is a pin for the user. The PIN may be 4 to 128 international characters in length, depending on restrictions of the PIN policy.
11
+ # @return [Hash] A hash that contains: :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
12
+ def create(client, user_id, pin)
13
+ message = {
14
+ 'vip:requestId': Utilities.get_request_id('create_user'),
15
+ 'vip:userId': user_id
16
+ }
17
+
18
+ unless pin.nil?
19
+ message['vip:pin'] = pin
20
+ end
21
+
22
+ response = client.call(:create_user, message: message)
23
+
24
+ get_return_hash(response.body[:create_user_response])
25
+ end
26
+
27
+
28
+ # Delete a user from the database of Symantec VIP users.
29
+ #
30
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
31
+ # @param [String] user_id Id of the user to delete.
32
+ # @return [Hash] A hash that contains: :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
33
+ def delete(client, user_id)
34
+ response = client.call(:delete_user,
35
+ message: {
36
+ 'vip:requestId': Utilities.get_request_id('delete_user'),
37
+ 'vip:userId': user_id
38
+ })
39
+
40
+ get_return_hash(response.body[:delete_user_response])
41
+ end
42
+
43
+
44
+ # Creates the body for a add credential request.
45
+ #
46
+ # @param [String] user_id Id of the user to add a credential to.
47
+ # @param [String] credential_id
48
+ # @param [String] credential_type must be one of the keys to the credential types from the Utilities class.
49
+ # @see Utilities::CREDENTIAL_TYPES
50
+ # @param [Hash] options A hash that can contain the following. :name adds a friendly name to the credential added to vip, :otp sends a otp from the credential with the request to verify that the user actually has possession of the credential
51
+ # @return [Hash] A hash representing the body of the soap request to add a credential.
52
+ def get_add_credential_message(user_id, credential_id, credential_type, options)
53
+ message = {
54
+ 'vip:requestId': Utilities.get_request_id('add_credential'),
55
+ 'vip:userId': user_id
56
+ }
57
+
58
+ credential_detail = {
59
+ 'vip:credentialId': credential_id,
60
+ 'vip:credentialType': credential_type
61
+ }
62
+
63
+ unless options == nil
64
+ if options.key?(:name)
65
+ credential_detail[:'vip:friendlyName'] = options[:name]
66
+ end
67
+
68
+ if options.key?(:otp)
69
+ message[:'vip:otpAuthData'] = {
70
+ 'vip:otp': options[:otp]
71
+ }
72
+ end
73
+ end
74
+
75
+ message[:'vip:credentialDetail'] = credential_detail
76
+
77
+ message
78
+ end
79
+
80
+
81
+ # Add a credential to an existing user in the Symantec VIP database.
82
+ #
83
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
84
+ # @param [String] user_id Id of the user to add a credential to.
85
+ # @param [String] credential_id Unique identifier of the credential.
86
+ # @param [String] credential_type must be one of the keys to the credential types from the Utilities class.
87
+ # @see Utilities::CREDENTIAL_TYPES
88
+ # @param [Hash] options A hash that can contain the following. :name adds a friendly name to the credential added to vip, :otp sends a otp from the credential with the request to verify that the user actually has possession of the credential
89
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
90
+ def add_credential(client, user_id, credential_id, credential_type, options)
91
+ response = client.call(:add_credential, message: get_add_credential_message(user_id, credential_id, credential_type, options))
92
+ get_return_hash(response.body[:add_credential_response])
93
+ end
94
+
95
+
96
+ # Remove a credential from a given user. If the Device deletion policy for Remembered Devices is set to Admin Only,
97
+ # credentials can only be removed through VIP Manager. The removeCredential API will return the error 6010: This
98
+ # account is not authorized to perform the requested operation
99
+ #
100
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
101
+ # @param [String] user_id Id of the user to remove a credential from.
102
+ # @param [String] credential_id Unique identifier of the credential.
103
+ # @param [String] credential_type must be one of the keys to the credential types from the Utilities class.
104
+ # @see Utilities::CREDENTIAL_TYPES
105
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
106
+ def remove_credential(client, user_id, credential_id, credential_type)
107
+ response = client.call(:remove_credential, message: {
108
+ 'vip:requestId': Utilities.get_request_id('remove_credential'),
109
+ 'vip:userId': user_id,
110
+ 'vip:credentialId': credential_id,
111
+ 'vip:credentialType': credential_type
112
+ })
113
+
114
+ get_return_hash(response.body[:remove_credential_response])
115
+ end
116
+
117
+
118
+ # Updates the friendly name of a users credential.
119
+ #
120
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
121
+ # @param [String] user_id Id of the user to remove a credential from.
122
+ # @param [String] credential_id Unique identifier of the credential.
123
+ # @param [String] credential_type must be one of the keys to the credential types from the Utilities class.
124
+ # @see Utilities::CREDENTIAL_TYPES
125
+ # @param [Object] name A user-defined name to identify the credential.
126
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
127
+ def update_credential(client, user_id, credential_id, credential_type, name)
128
+ response = client.call(:update_credential, message: {
129
+ 'vip:requestId': Utilities.get_request_id('update_credential'),
130
+ 'vip:userId': user_id,
131
+ 'vip:credentialId': credential_id,
132
+ 'vip:credentialType': credential_type,
133
+ 'vip:friendlyName': name
134
+ })
135
+
136
+ get_return_hash(response.body[:update_credential_response])
137
+ end
138
+
139
+
140
+ # Get all the credentials that have been last bound to a user or the last authentication, as well as the friendly
141
+ # name for the user's credential.
142
+ #
143
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP query WSDL.
144
+ # @param [String] user_id Id of the user to get information about.
145
+ # @param [Boolean] include_push If the users push details should be returned.
146
+ # @return [Hash] A hash that contains; :credentials a array of credentials available, :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
147
+ def get_user_info(client, user_id, include_push)
148
+ response = client.call(:get_user_info, message: {
149
+ 'vip:requestId': Utilities.get_request_id('get_user_info'),
150
+ 'vip:userId': user_id,
151
+ 'vip:includePushAttributes': include_push
152
+ })
153
+
154
+ response_hash = response.body[:get_user_info_response]
155
+
156
+ credentials = []
157
+
158
+ if response_hash[:num_bindings] == nil || response_hash[:num_bindings] == '0'
159
+ credentials = nil
160
+
161
+ else
162
+ response_hash[:credential_binding_detail].each do |credential|
163
+
164
+ bind_detail = credential[:binding_detail]
165
+
166
+ if credential[:credential_type] == 'STANDARD_OTP'
167
+ push_attrs = credential[:push_attributes]
168
+ credentials.push({
169
+ type: 'STANDARD_OTP',
170
+ enabled: response_hash[:credential_status] == 'ENABLED' && bind_detail[:bind_status] == 'ENABLED',
171
+ friendly_name: bind_detail[:friendly_name],
172
+ push: push_check(push_attrs),
173
+ credential_id: credential[:credential_id]
174
+ })
175
+
176
+ elsif credential[:credential_type] == 'SMS_OTP'
177
+ credentials.push({
178
+ type: 'SMS_OTP',
179
+ enabled: response_hash[:credential_status] == 'ENABLED' && bind_detail[:bind_status] == 'ENABLED',
180
+ friendly_name: bind_detail[:friendly_name],
181
+ push: false,
182
+ credential_id: credential[:credential_id]
183
+ })
184
+ elsif credential[:credential_type] == 'VOICE_OTP'
185
+ credentials.push({
186
+ type: 'VOICE_OTP',
187
+ enabled: response_hash[:credential_status] == 'ENABLED' && bind_detail[:bind_status] == 'ENABLED',
188
+ friendly_name: bind_detail[:friendly_name],
189
+ push: false,
190
+ credential_id: credential[:credential_id]
191
+ })
192
+ end
193
+
194
+ end
195
+
196
+ end
197
+
198
+ ret = get_return_hash(response_hash)
199
+ ret[:credentials] = credentials
200
+ ret
201
+ end
202
+
203
+
204
+ # Use updateUser to update information about a user in VIP User Services.
205
+ #
206
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
207
+ # @param [String] user_id The unique ID for the user.
208
+ # @param [Object] options
209
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
210
+ def update_user(client, user_id, options)
211
+ message = {
212
+ 'vip:requestId': Utilities.get_request_id('update_user'),
213
+ 'vip:userId': user_id
214
+ }
215
+
216
+ unless options == nil
217
+ if options.key?(:newId)
218
+ message[:'vip:newUserId'] = options[:newId]
219
+ end
220
+
221
+ if options.key?(:status)
222
+ message[:'vip:newUserStatus'] = options[:status]
223
+ end
224
+
225
+ if options.key?(:oldPin)
226
+ message[:'vip:oldPin'] = options[:oldPin]
227
+ end
228
+
229
+ if options.key?(:newPin)
230
+ message[:'vip:newPin'] = options[:newPin]
231
+ end
232
+
233
+ if options.key?(:pinReset)
234
+ message[:'vip:forcePinReset'] = options[:pinReset]
235
+ end
236
+
237
+ end
238
+
239
+ response = client.call(:update_user, message: message)
240
+ get_return_hash(response.body[:update_user_response])
241
+ end
242
+
243
+
244
+ # Use clearUserPin to remove an assigned PIN from a user.
245
+ #
246
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
247
+ # @param [String] user_id The unique ID for the user.
248
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
249
+ def clear_user_pin(client, user_id)
250
+ response = client.call(:clear_user_pin, message: {
251
+ 'vip:requestId': Utilities.get_request_id('clear_pin'),
252
+ 'vip:userId': user_id
253
+ })
254
+
255
+ get_return_hash(response.body[:clear_user_pin_response])
256
+ end
257
+
258
+
259
+ # Use setTemporaryPasswordAttributes to change the expiration date for a temporary security code you previously set.
260
+ #
261
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
262
+ # @param [String] user_id The unique ID for the user.
263
+ # @param [Object] options
264
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
265
+ def set_temp_pass_attr(client, user_id, options)
266
+ message = {
267
+ 'vip:requestId': Utilities.get_request_id('set_temp_pass_attr'),
268
+ 'vip:userId': user_id
269
+ }
270
+
271
+ unless options == nil
272
+ inner = {}
273
+ if options.key?(:oneTime)
274
+ inner[:'vip:oneTimeUseOnly'] = options[:oneTime]
275
+ end
276
+
277
+ if options.key?(:expireTime)
278
+ inner[:'vip:expirationTime'] = options[:expireTime]
279
+ end
280
+
281
+ message[:'vip:temporaryPasswordAttributes'] = inner
282
+ end
283
+
284
+ response = client.call(:set_temporary_password_attributes, message: message)
285
+ get_return_hash(response.body[:set_temporary_password_attributes_response])
286
+ end
287
+
288
+
289
+ # Use getTemporaryPasswordAttributes to poll VIP User Services every three to five seconds to check the status of a
290
+ # push notification. The push notification is validated against the notification’s unique transaction ID.
291
+ #
292
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP query WSDL.
293
+ # @param [String] user_id The unique ID for the user.
294
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
295
+ def get_temp_pass_attr(client, user_id)
296
+ response = client.call(:get_temporary_password_attributes, message: {
297
+ 'vip:requestId': Utilities.get_request_id('get_temp_pass_attr'),
298
+ 'vip:userId': user_id
299
+ })
300
+ response_hash = response.body[:get_temporary_password_attributes_response]
301
+
302
+ ret = get_return_hash(response_hash)
303
+
304
+ unless response_hash[:temp_pwd_attributes] == nil
305
+ ret[:oneTime] = response_hash[:temp_pwd_attributes][:one_time_use_only]
306
+ ret[:expiration] = response_hash[:temp_pwd_attributes][:expiration_time]
307
+ end
308
+
309
+ ret
310
+ end
311
+
312
+
313
+ # Use setTemporaryPassword to set a temporary security code for a user. You can optionally set an
314
+ # expiration date for the security code, or set it for one-time use only. The request requires the user ID and
315
+ # optionally, the temporary security code string. If you do not provide a security code, VIP User Services generates
316
+ # one for you.
317
+ #
318
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
319
+ # @param [String] user_id The unique ID for the user.
320
+ # @param [Int] phone The phone or mobile device number to which the VIP User Service should deliver the security code.
321
+ # @param [Hash] options
322
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
323
+ def set_temp_password(client, user_id, phone, options)
324
+ message = {
325
+ 'vip:requestId': Utilities.get_request_id('set_temp_pass'),
326
+ 'vip:userId': user_id
327
+ }
328
+
329
+ phone_options = {'vip:phoneNumber': phone}
330
+
331
+ unless options == nil
332
+ if options.key?(:otp)
333
+ message[:'vip:temporaryPassword'] = options[:otp]
334
+ end
335
+
336
+ if options.key?(:expireTime)
337
+ message[:'vip:expirationTime'] = options[:expireTime]
338
+ end
339
+
340
+ if options.key?(:oneTime)
341
+ message[:'vip:temporaryPasswordAttributes'] = { 'vip:oneTimeUseOnly': options[:oneTime] }
342
+ end
343
+
344
+ if options.key?(:from)
345
+ phone_options[:'vip:expirationTime'] = options[:from]
346
+ end
347
+ end
348
+
349
+ message[:'vip:smsDeliveryInfo'] = phone_options
350
+
351
+ response = client.call(:set_temporary_password, message: message)
352
+
353
+ ret = get_return_hash(response.body[:set_temporary_password_response])
354
+ ret[:password] = response.body[:set_temporary_password_response][:temporary_password]
355
+
356
+ ret
357
+ end
358
+
359
+
360
+ # Use clearTemporaryPassword to add users to VIP User Services.to remove a temporary security code from a user. If the
361
+ # user attempts to use a temporary security that has been cleared, VIP User Services returns an error stating the
362
+ # security code is not set. If the user validates a security code using a valid credential, any temporary security
363
+ # code that is set for that user is automatically cleared.
364
+ #
365
+ # @param [Savon::Client] client A Savon client object to make the call with. This needs to be created with the VIP management WSDL.
366
+ # @param [String] user_id The unique ID for the user.
367
+ # @return [Hash] A hash that contains; :success a boolean if the call succeeded, :message a string with any error message, :id the id of the call for debugging purposes
368
+ def clear_temp_pass(client, user_id)
369
+ message = {
370
+ 'vip:requestId': Utilities.get_request_id('clear_temp_pass'),
371
+ 'vip:userId': user_id
372
+ }
373
+
374
+ response = client.call(:clear_temporary_password, message: message)
375
+ get_return_hash(response.body[:clear_temporary_password_response])
376
+ end
377
+
378
+
379
+ # Helper function to loop through an array of hashes with key value pairs and return if push is enabled.
380
+ #
381
+ # @param [Array] attrs A array of hash attributes
382
+ # @return [Boolean] If push is enabled for the give attributes
383
+ def push_check(attrs)
384
+ attrs.each do |a|
385
+ if a[:key] == 'PUSH_ENABLED'
386
+ return a[:value]
387
+ end
388
+ end
389
+ false
390
+ end
391
+
392
+
393
+ # Helper function to create the hash to return. All user calls have the same return values.
394
+ #
395
+ # @param [Hash] response_hash
396
+ # @return [Hash] A hash with the appropriate values. Included are: :success - a boolean if the operation was successful,
397
+ def get_return_hash(response_hash)
398
+ success = response_hash[:status] == '0000'
399
+
400
+ {
401
+ success: success,
402
+ message: response_hash[:status_message],
403
+ id: response_hash[:request_id]
404
+ }
405
+ end
406
+
407
+ end
408
+
409
+ end