TeleAuth 0.5
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/README +106 -0
- data/lib/teleauth.rb +251 -0
- data/tests/ts_teleauth.rb +54 -0
- metadata +41 -0
data/README
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
== Synopsis
|
2
|
+
|
3
|
+
Ruby TeleAuth Module.
|
4
|
+
|
5
|
+
Allows for two-factor authentication within Ruby. Uses the
|
6
|
+
TeleAuth[http://www.teleauth.com] service.
|
7
|
+
|
8
|
+
== Author
|
9
|
+
|
10
|
+
Mohit Muthanna Cheppudira <mohit AT muthanna DOTcom>
|
11
|
+
|
12
|
+
== Copyright
|
13
|
+
|
14
|
+
Copyright (c) 2005 Mohit Muthanna Cheppudira.
|
15
|
+
Licensed under the GPL.
|
16
|
+
|
17
|
+
== Prerequisites
|
18
|
+
|
19
|
+
To use this module, you will need a TeleAuth API Key. Get yours
|
20
|
+
at [http://www.teleauth.com].
|
21
|
+
|
22
|
+
== Basic Usage
|
23
|
+
|
24
|
+
The following example calls a user on a specific phone
|
25
|
+
number and requests a PIN code.
|
26
|
+
|
27
|
+
require 'teleauth'
|
28
|
+
|
29
|
+
conn = TeleAuth::Client.new (
|
30
|
+
'urls' = ['http://teleauth.com/api/auth'],
|
31
|
+
'domain_id' = 'mydomain',
|
32
|
+
'login' = 'dialer',
|
33
|
+
'password' = 'bu4ger'
|
34
|
+
)
|
35
|
+
|
36
|
+
Register a user's phone number.
|
37
|
+
|
38
|
+
conn.register_phone(
|
39
|
+
'ext_uid' => 'foobar',
|
40
|
+
'phone' => '12332445443'
|
41
|
+
)
|
42
|
+
|
43
|
+
Call user and request PIN code.
|
44
|
+
|
45
|
+
conn.get_secret( 'ext_uid' => 'foobar' ) { |response|
|
46
|
+
puts "PIN code: #{ response['secret'] }"
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
== TeleAuth API
|
51
|
+
|
52
|
+
In brief, you can use any API command as a TeleAuth::Client
|
53
|
+
method. Arguments are provided as hash parameters. Responses
|
54
|
+
are returned as Ruby hashes.
|
55
|
+
|
56
|
+
Examples:
|
57
|
+
|
58
|
+
response = conn.validate_user
|
59
|
+
|
60
|
+
conn.validate_user { |response|
|
61
|
+
# do something
|
62
|
+
}
|
63
|
+
|
64
|
+
Register a user's phone number and PIN code.
|
65
|
+
|
66
|
+
conn.register_phone(
|
67
|
+
'ext_uid' => 'foobar',
|
68
|
+
'phone' => '12332445443',
|
69
|
+
'pin' => '45334',
|
70
|
+
)
|
71
|
+
|
72
|
+
Call the user and validate PIN
|
73
|
+
|
74
|
+
conn.validate_phone( 'ext_uid' => 'foobar' ) { |response|
|
75
|
+
if response['login'] == 'PASS'
|
76
|
+
puts "Valid PIN code."
|
77
|
+
else
|
78
|
+
puts "Authorization failed"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
For the TeleAuth API reference, visit http://teleauth.com
|
84
|
+
|
85
|
+
== Logging, Exceptions and Errors
|
86
|
+
|
87
|
+
The class raises the TeleAuth::APIError exception if the API command
|
88
|
+
failed.
|
89
|
+
|
90
|
+
If you have multiple URLs, eg. for failover, the module can
|
91
|
+
inform you if a failover took place.
|
92
|
+
|
93
|
+
conn.on_command_fail { |url|
|
94
|
+
puts "Failed to connect to #{ url }. Trying next one."
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
If you need nice debug output, use on_log:
|
99
|
+
|
100
|
+
con.on_log { |msg|
|
101
|
+
$stderr.puts( "LOG: #{ msg }" )
|
102
|
+
end
|
103
|
+
|
104
|
+
== Support
|
105
|
+
|
106
|
+
Get on the {TeleAuth Mailing List}[http://lists.sourceforge.net/lists/listinfo/teleauth-users]
|
data/lib/teleauth.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'yaml'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
|
7
|
+
== Synopsis
|
8
|
+
|
9
|
+
Ruby TeleAuth Module.
|
10
|
+
$Id$
|
11
|
+
|
12
|
+
Allows for two-factor authentication within Ruby. Uses the
|
13
|
+
TeleAuth[http://www.teleauth.com] service.
|
14
|
+
|
15
|
+
== Author
|
16
|
+
|
17
|
+
Mohit Muthanna Cheppudira mohit AT muthanna DOT com
|
18
|
+
|
19
|
+
== Copyright
|
20
|
+
|
21
|
+
Copyright (c) 2005 Mohit Muthanna Cheppudira.
|
22
|
+
Licensed under the GPL.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
module TeleAuth
|
27
|
+
|
28
|
+
=begin rdoc
|
29
|
+
This exception is raised if an API command could
|
30
|
+
not be successfully sent to any of the TeleAuth
|
31
|
+
URLs.
|
32
|
+
=end
|
33
|
+
|
34
|
+
class APIError < Exception; end
|
35
|
+
|
36
|
+
=begin rdoc
|
37
|
+
|
38
|
+
This is the TeleAuth Client Class. Basic usage:
|
39
|
+
|
40
|
+
The following example calls a user on a specific phone
|
41
|
+
number and requests a PIN code.
|
42
|
+
|
43
|
+
require 'teleauth'
|
44
|
+
|
45
|
+
conn = TeleAuth::Client.new (
|
46
|
+
'urls' = ['http://teleauth.com/api/auth'],
|
47
|
+
'domain_id' = 'mydomain',
|
48
|
+
'login' = 'dialer',
|
49
|
+
'password' = 'bu4ger'
|
50
|
+
)
|
51
|
+
|
52
|
+
# Register a user's phone number.
|
53
|
+
conn.register_phone(
|
54
|
+
'ext_uid' => 'foobar',
|
55
|
+
'phone' => '12332445443'
|
56
|
+
)
|
57
|
+
|
58
|
+
conn.get_secret( 'ext_uid' => 'foobar' ) { |response|
|
59
|
+
puts "PIN code: #{ response['secret'] }"
|
60
|
+
}
|
61
|
+
|
62
|
+
=end
|
63
|
+
|
64
|
+
class Client
|
65
|
+
|
66
|
+
=begin rdoc
|
67
|
+
[auth] A hash that consists of API authentication parameters.
|
68
|
+
[urls] An array of API URLs.
|
69
|
+
=end
|
70
|
+
|
71
|
+
attr_accessor :auth, :urls
|
72
|
+
|
73
|
+
=begin rdoc
|
74
|
+
At a minimum, this method requires a list of URLs, and
|
75
|
+
the API Key, like so:
|
76
|
+
|
77
|
+
|
78
|
+
conn = TeleAuth::Client.new(
|
79
|
+
"urls" => ["http://teleauth.com/apu/auth", "http://backup.teleauth.com/api/auth"],
|
80
|
+
"domain_id" => "public.sample",
|
81
|
+
"login" => "admin",
|
82
|
+
"password" => "p4ss"
|
83
|
+
)
|
84
|
+
|
85
|
+
The URLs are a list of primary and failover API servers. When
|
86
|
+
an API command is sent, each of these servers are cycled through
|
87
|
+
until one of them works.
|
88
|
+
=end
|
89
|
+
|
90
|
+
def initialize( params = {} )
|
91
|
+
if params.has_key?( 'urls' )
|
92
|
+
self.urls = params['urls']
|
93
|
+
|
94
|
+
# Delete this key, as it shouldn't be passed in
|
95
|
+
# the API request.
|
96
|
+
params.delete( 'urls' )
|
97
|
+
else
|
98
|
+
self.urls = []
|
99
|
+
end
|
100
|
+
|
101
|
+
@auth = params
|
102
|
+
@on_command_fail = proc {}
|
103
|
+
@on_log = proc {}
|
104
|
+
end
|
105
|
+
|
106
|
+
=begin rdoc
|
107
|
+
Setup a code-block to execute if one of the URLs fail. This could
|
108
|
+
be useful for logging, for example. It passes the URL of the API
|
109
|
+
server that failed.
|
110
|
+
|
111
|
+
conn.on_command_fail { |url|
|
112
|
+
$stderr.puts "Failed to send command to #{ url }"
|
113
|
+
}
|
114
|
+
=end
|
115
|
+
|
116
|
+
def on_command_fail( &block )
|
117
|
+
@on_command_fail = block
|
118
|
+
end
|
119
|
+
|
120
|
+
=begin rdoc
|
121
|
+
Our logger. Call this and specify a logging routing to receive more
|
122
|
+
debug information.
|
123
|
+
|
124
|
+
conn.on_log { |msg|
|
125
|
+
$stderr.puts "LOG: #{ msg }"
|
126
|
+
end
|
127
|
+
=end
|
128
|
+
|
129
|
+
def on_log( &block )
|
130
|
+
@on_log = block
|
131
|
+
end
|
132
|
+
|
133
|
+
def log( *args )
|
134
|
+
@on_log.call( *args )
|
135
|
+
end
|
136
|
+
|
137
|
+
=begin rdoc
|
138
|
+
The main communications routine. Establish a connection to the API
|
139
|
+
server, and send the command. Private.
|
140
|
+
=end
|
141
|
+
|
142
|
+
def api_send( command_hash )
|
143
|
+
|
144
|
+
# For each URL...
|
145
|
+
@urls.each do |url|
|
146
|
+
log( "Trying #{ url }" )
|
147
|
+
uri = URI.parse( url )
|
148
|
+
|
149
|
+
# Make sure it's HTTP/(S) ...
|
150
|
+
if uri.scheme == "http"
|
151
|
+
response = ""
|
152
|
+
|
153
|
+
# Build the POST parameters..
|
154
|
+
post_params = command_hash.keys.collect { |key|
|
155
|
+
key + "=" + command_hash[key]
|
156
|
+
}.join( "&" )
|
157
|
+
|
158
|
+
log( "Sending: #{ post_params }" )
|
159
|
+
|
160
|
+
begin
|
161
|
+
Net::HTTP.start( uri.host ) do |query|
|
162
|
+
response = query.post( uri.path, post_params )
|
163
|
+
end
|
164
|
+
|
165
|
+
log( "Response: #{ response.message }" )
|
166
|
+
|
167
|
+
if response.message == "OK"
|
168
|
+
log( "Body: #{ response.body }" )
|
169
|
+
return response.body
|
170
|
+
else
|
171
|
+
# HTTP level failure...
|
172
|
+
@on_command_fail.call( url )
|
173
|
+
next
|
174
|
+
end
|
175
|
+
rescue Exception => e
|
176
|
+
# Socket level failure...
|
177
|
+
@on_command_fail.call( url )
|
178
|
+
next
|
179
|
+
end
|
180
|
+
else
|
181
|
+
# Unsupported URI scheme...
|
182
|
+
@on_command_fail.call( url )
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# All failed. Return Nil.
|
187
|
+
return nil
|
188
|
+
end
|
189
|
+
|
190
|
+
=begin rdoc
|
191
|
+
This method creates a hash with parameters for api_send
|
192
|
+
=end
|
193
|
+
def send_command( *args )
|
194
|
+
# Extract the instance method name
|
195
|
+
command = args.shift
|
196
|
+
|
197
|
+
# No Arguments?
|
198
|
+
if (params = args.shift).nil?
|
199
|
+
params = Hash.new
|
200
|
+
end
|
201
|
+
|
202
|
+
# Pass the extracted method name as the API command
|
203
|
+
command_hash = auth.merge( params ).merge( 'cmd' => command.to_s )
|
204
|
+
response = api_send( command_hash )
|
205
|
+
|
206
|
+
raise APIError if response.nil?
|
207
|
+
response
|
208
|
+
end
|
209
|
+
|
210
|
+
=begin rdoc
|
211
|
+
Check to see if we have connectivity by sending a "version" API command.
|
212
|
+
=end
|
213
|
+
|
214
|
+
def ping?
|
215
|
+
begin
|
216
|
+
version
|
217
|
+
rescue Exception => e
|
218
|
+
return false
|
219
|
+
end
|
220
|
+
|
221
|
+
true
|
222
|
+
end
|
223
|
+
|
224
|
+
=begin rdoc
|
225
|
+
This is where the magic happens. Any instance method that is not defined
|
226
|
+
reaches here. We just propogate the request to send_command, which
|
227
|
+
extracts the method name, and substitutes it for the API command. This
|
228
|
+
get's fed to api_send.
|
229
|
+
|
230
|
+
This function also yields to a code block, so commands can be sent in
|
231
|
+
multiple forms:
|
232
|
+
|
233
|
+
conn.get_user_list { |user_list|
|
234
|
+
# ... do something with user_list
|
235
|
+
}
|
236
|
+
|
237
|
+
or
|
238
|
+
|
239
|
+
user_list = conn.get_user_list
|
240
|
+
=end
|
241
|
+
|
242
|
+
def method_missing( *args )
|
243
|
+
response = YAML::load( send_command( *args ) )
|
244
|
+
yield response if block_given?
|
245
|
+
response
|
246
|
+
end
|
247
|
+
|
248
|
+
protected :api_send, :log
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# PickAxe magic. Helps run tests from any directory.
|
4
|
+
$:.unshift File.join( File.dirname( __FILE__ ), "..", "lib" )
|
5
|
+
|
6
|
+
require 'teleauth'
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
include TeleAuth
|
10
|
+
|
11
|
+
=begin rdoc
|
12
|
+
Test class for TeleAuth::Client.
|
13
|
+
=end
|
14
|
+
|
15
|
+
class TestClient < Test::Unit::TestCase
|
16
|
+
def setup
|
17
|
+
|
18
|
+
# Setup API Test parameters here. Make sure
|
19
|
+
# you use an invalid URL before a valid one
|
20
|
+
# to test failures.
|
21
|
+
|
22
|
+
@conn = Client.new(
|
23
|
+
"urls" => ["http://abc.d/f", "http://teleauth.com/api/auth"],
|
24
|
+
"domain_id" => "public.test",
|
25
|
+
"login" => "reader",
|
26
|
+
"password" => "reader"
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
# Nothing to do...
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_ping
|
35
|
+
assert_equal( @conn.ping?, true )
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_commands
|
39
|
+
failed = false
|
40
|
+
@conn.on_command_fail {
|
41
|
+
failed = true
|
42
|
+
}
|
43
|
+
|
44
|
+
# Test both formats of commands...
|
45
|
+
assert_equal( @conn.validate_user['result'], 'OK' )
|
46
|
+
|
47
|
+
@conn.validate_user { |response|
|
48
|
+
assert_equal response['result'], 'OK'
|
49
|
+
}
|
50
|
+
|
51
|
+
# The first URL should have failed.
|
52
|
+
assert_equal failed, true
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: TeleAuth
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.5"
|
7
|
+
date: 2005-08-26
|
8
|
+
summary: Ruby library for the TeleAuth authentication system. Requires a TeleAuth API key.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: mohit@muthanna.com
|
12
|
+
homepage: http://teleauth.com
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: teleauth
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Mohit Muthanna Cheppudira
|
29
|
+
files:
|
30
|
+
- lib/teleauth.rb
|
31
|
+
- tests/ts_teleauth.rb
|
32
|
+
- README
|
33
|
+
test_files:
|
34
|
+
- tests/ts_teleauth.rb
|
35
|
+
rdoc_options: []
|
36
|
+
extra_rdoc_files:
|
37
|
+
- README
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
requirements: []
|
41
|
+
dependencies: []
|