els_token 1.0.1 → 1.2.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/README.rdoc +12 -2
- data/lib/els_token.rb +209 -113
- data/lib/els_token/{els_user.rb → els_identity.rb} +15 -6
- data/lib/els_token/version.rb +1 -1
- data/test/dummy/Gemfile +9 -0
- data/test/dummy/Gemfile.lock +17 -1
- data/test/dummy/app/assets/javascripts/application.js +1 -2
- data/test/dummy/app/assets/javascripts/els_session.js.coffee +7 -0
- data/test/dummy/app/controllers/application_controller.rb +45 -6
- data/test/dummy/app/controllers/els_session_controller.rb +91 -0
- data/test/dummy/app/models/els_faker.rb +8 -0
- data/test/dummy/app/views/els_session/new.html.erb +41 -0
- data/test/dummy/app/views/els_session/show.html.erb +4 -0
- data/test/dummy/app/views/layouts/application.html.erb +6 -1
- data/test/dummy/config/application.rb +3 -39
- data/test/dummy/config/els_token.yml +21 -0
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/uat.rb +67 -0
- data/test/dummy/config/initializers/els_token.rb +1 -1
- data/test/dummy/config/routes.rb +9 -55
- data/test/dummy/log/development.log +2170 -4
- data/test/dummy/tmp/cache/assets/C65/500/sprockets%2F53516304d6d54f9499b5a7788631e5c5 +0 -0
- data/test/dummy/tmp/cache/assets/CA6/630/sprockets%2F8af9c2296e34c4f01a58747a12c07130 +0 -0
- data/test/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/D49/140/sprockets%2Fd128539bcb29d65cf7e28a43f8563a2f +0 -0
- data/test/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/D9C/D00/sprockets%2F66ef3d03a58dfcc273e3453b04fdf81b +0 -0
- data/test/dummy/tmp/cache/assets/D9F/AA0/sprockets%2Fab395cb72ff1e290f0de1f739a87bd50 +0 -0
- data/test/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- metadata +41 -54
- data/test/dummy/app/assets/javascripts/hello.js +0 -2
- data/test/dummy/app/assets/stylesheets/hello.css +0 -4
- data/test/dummy/app/controllers/hello_controller.rb +0 -4
- data/test/dummy/app/views/hello/index.html.erb +0 -1
- data/test/dummy/config/els.yml +0 -12
- data/test/els_token_test.rb.old +0 -7
- data/test/hello_controller_test.rb +0 -32
data/README.rdoc
CHANGED
@@ -4,8 +4,16 @@ A simple library for interfacing with forgeRock OpenAM REST Interface.
|
|
4
4
|
|
5
5
|
Still pretty much in development but kind of workable.
|
6
6
|
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
include ElsToken into your class or module
|
10
|
+
|
7
11
|
change log
|
8
12
|
|
13
|
+
1.2.0
|
14
|
+
Removed Rails dependency.
|
15
|
+
Cleaned up instructions - getting ready to bare all :)
|
16
|
+
|
9
17
|
1.0.1
|
10
18
|
Removed AOLMemberCA certificate as it was mostly pointless
|
11
19
|
SSL without verification is used as default
|
@@ -15,5 +23,7 @@ change log
|
|
15
23
|
Initial release :)
|
16
24
|
|
17
25
|
= TODO
|
18
|
-
|
19
|
-
|
26
|
+
With the correct level of priviledge it's possible to perform granular LDAP searches against the OpenAM REST interface.
|
27
|
+
By Default one can only pull identity details for a provided token but it might be nice to search against other attributes.
|
28
|
+
|
29
|
+
Erm some tests might be nice :)
|
data/lib/els_token.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'els_token/module_inheritable_attributes'
|
2
|
-
require 'els_token/
|
2
|
+
require 'els_token/els_identity'
|
3
3
|
require 'net/http'
|
4
4
|
require 'uri'
|
5
5
|
|
@@ -14,142 +14,238 @@ module ElsToken
|
|
14
14
|
|
15
15
|
module ClassMethods
|
16
16
|
|
17
|
-
# els_config expects a
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
17
|
+
# els_config expects a hash with environmental
|
18
|
+
# parameters including the els gateway and expected
|
19
|
+
# cookie name (when used in a Rack environment)
|
20
|
+
# An optional fake identity can be supplied which
|
21
|
+
# will override any active authentication. This can
|
22
|
+
# be especially useful during automated testing.
|
23
|
+
# The fake ID can take any of the ElsIdentity properties
|
24
|
+
#
|
25
|
+
# A typical setup would initialize a options hash to
|
26
|
+
# include the following
|
27
|
+
#
|
28
|
+
# faker:
|
29
|
+
# name: neilcuk
|
30
|
+
# employee_number: 09095
|
31
|
+
# roles:
|
32
|
+
# - App Admins
|
33
|
+
# - Domain Users
|
34
|
+
# uri: https://els-admin.corp.aol.com:443/opensso/identity
|
35
|
+
# cookie: iPlanetDirectoryPro
|
36
|
+
# cert: /path/to/certs
|
37
|
+
#
|
38
|
+
# Do not include the faker object in your production
|
39
|
+
# configuration :)
|
40
|
+
#
|
41
|
+
# only the uri option is required if you are not worried
|
42
|
+
# about cookies and do not plan on using them. If you want
|
43
|
+
# to include a certificate for interacting with the ELS
|
44
|
+
# server then you can specify a file or directory to find
|
45
|
+
# the cert. By default Certificate validiation is off!
|
23
46
|
#
|
24
|
-
# class MyController
|
25
|
-
# include ElsToken
|
26
|
-
# els_config options_hash
|
27
|
-
# end
|
28
47
|
def els_config(options = {})
|
29
|
-
|
48
|
+
unless options["uri"]
|
49
|
+
raise "I need a uri to authenticate against" unless options["faker"]
|
50
|
+
end
|
51
|
+
els_options.merge!(options)
|
30
52
|
end
|
31
|
-
|
32
|
-
|
53
|
+
|
54
|
+
def els_uri(uri = nil)
|
55
|
+
return els_options["uri"] unless uri
|
56
|
+
els_options["uri"] = uri
|
57
|
+
end
|
58
|
+
|
59
|
+
def els_cookie_name(cookie_name = nil)
|
60
|
+
return els_options["cookie"] unless cookie_name
|
61
|
+
els_options["cookie_name"] = uri
|
62
|
+
end
|
63
|
+
|
64
|
+
def els_faker(faker = {})
|
65
|
+
els_options["faker"] = faker
|
66
|
+
end
|
67
|
+
|
68
|
+
def els_options
|
69
|
+
@els_options
|
70
|
+
end
|
71
|
+
|
72
|
+
# authenticates against ELS and returns the user token
|
73
|
+
def authenticate(username,password,options={})
|
33
74
|
|
34
|
-
|
35
|
-
|
75
|
+
begin
|
76
|
+
response = els_http_request("/authenticate",
|
77
|
+
"uri=realm=aolcorporate&username=#{username}&password=#{password}",
|
78
|
+
options)
|
79
|
+
if response.code.eql? "200"
|
80
|
+
# return the token
|
81
|
+
response.body.chomp.sub(/token\.id=/,"")
|
82
|
+
else
|
83
|
+
raise response.error!
|
84
|
+
end
|
85
|
+
rescue Net::HTTPExceptions => e1
|
86
|
+
raise e1, "token retrieval failed for #{username}"
|
87
|
+
rescue Exception => e
|
88
|
+
# Do not expect these. Wrapping the exception so
|
89
|
+
# as to not reveal the passed in password
|
90
|
+
puts e.backtrace
|
91
|
+
raise e, "unable to fetch token for #{username}"
|
92
|
+
end
|
93
|
+
end
|
36
94
|
|
37
|
-
|
38
|
-
|
95
|
+
# passes a token to els to see if it is still valid
|
96
|
+
def is_token_valid?(token, options={})
|
97
|
+
response = els_http_request("/isTokenValid","tokenid=#{token}",options)
|
39
98
|
if response.code.eql? "200"
|
40
|
-
|
41
|
-
response.body.chomp.sub(/token\.id=/,"")
|
99
|
+
true
|
42
100
|
else
|
43
|
-
|
101
|
+
false
|
44
102
|
end
|
45
|
-
rescue Net::HTTPExceptions => e1
|
46
|
-
raise e1, "token retrieval failed for #{username}"
|
47
|
-
rescue Exception => e
|
48
|
-
# Do not expect these. Wrapping the exception so
|
49
|
-
# as to not reveal the passed in password
|
50
|
-
raise e, "unable to fetch token for #{username}"
|
51
103
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
false
|
104
|
+
|
105
|
+
|
106
|
+
# obtain a friendly ElsIdentity object by passing
|
107
|
+
# in a token
|
108
|
+
def get_token_identity(token,options={})
|
109
|
+
ElsIdentity.new(get_raw_token_identity(token,options))
|
60
110
|
end
|
61
|
-
end
|
62
111
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
token
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
112
|
+
# get_token_identity wraps the ELS identity response
|
113
|
+
# in a nice, friendly, object. If you don't like that object
|
114
|
+
# or need the raw data, then use this.
|
115
|
+
def get_raw_token_identity(token,options={})
|
116
|
+
response = els_http_request("/attributes","subjectid=#{token}",options)
|
117
|
+
if response.code.eql? "200"
|
118
|
+
response.body
|
119
|
+
else
|
120
|
+
response.error!
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# When used inside a rack environment
|
125
|
+
# will attempt to retrieve the user token
|
126
|
+
# from the session cookie and return a full
|
127
|
+
# identity. This is pretty much a convenience
|
128
|
+
# method that chains is_cookie_token_valid?
|
129
|
+
# then get_token_identity
|
130
|
+
def get_identity(token, options ={})
|
131
|
+
return fake_id if fake_it?
|
132
|
+
begin
|
133
|
+
if is_token_valid?(token, options)
|
134
|
+
get_token_identity(token, options)
|
135
|
+
else
|
136
|
+
raise "token is invalid"
|
137
|
+
end
|
138
|
+
rescue Exception => e
|
139
|
+
raise e
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def els_http_request(url_base_extension, query_string, options)
|
146
|
+
options = els_options.dup.merge(options)
|
147
|
+
uri = URI.parse(options['uri'] + url_base_extension)
|
148
|
+
uri.query=query_string
|
149
|
+
http = Net::HTTP.new(uri.host,uri.port)
|
150
|
+
http.use_ssl = true
|
151
|
+
|
152
|
+
# Use a known certificate if supplied
|
153
|
+
if rootca = options[:cert]
|
154
|
+
if File.exist? rootca
|
155
|
+
http.ca_file = rootca
|
156
|
+
elsif Dir.exist? rootca
|
157
|
+
http.ca.path = rootca
|
158
|
+
else
|
159
|
+
raise "${rootca} cannot be found"
|
160
|
+
end
|
161
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
162
|
+
http.verify_depth = 5
|
163
|
+
else
|
164
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
165
|
+
end
|
166
|
+
|
167
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
168
|
+
|
169
|
+
http.request(request)
|
170
|
+
end
|
171
|
+
|
172
|
+
def fake_it?
|
173
|
+
els_options.has_key? 'faker'
|
71
174
|
end
|
175
|
+
|
176
|
+
def fake_id
|
177
|
+
unless @fake_id
|
178
|
+
id = ElsIdentity.new
|
179
|
+
id.instance_variable_set("@roles",els_options['faker']['roles'])
|
180
|
+
id.instance_variable_set("@mail",els_options['faker']['mail'])
|
181
|
+
id.instance_variable_set("@last_name",els_options['faker']['last_name'])
|
182
|
+
id.instance_variable_set("@first_name",els_options['faker']['first_name'])
|
183
|
+
id.instance_variable_set("@uac",els_options['faker']['uac'])
|
184
|
+
id.instance_variable_set("@dn",els_options['faker']['dn'])
|
185
|
+
id.instance_variable_set("@common_name",els_options['faker']['common_name'])
|
186
|
+
id.instance_variable_set("@employee_number",els_options['faker']['employee_number'])
|
187
|
+
id.instance_variable_set("@display_name",els_options['faker']['display_name'])
|
188
|
+
id.instance_variable_set("@token_id",els_options['faker']['token_id'])
|
189
|
+
id.instance_variable_set("@user_status",els_options['faker']['user_status'])
|
190
|
+
@fake_id = id
|
191
|
+
end
|
192
|
+
@fake_id
|
193
|
+
end
|
72
194
|
end
|
73
195
|
|
74
|
-
#
|
196
|
+
# Instance methods
|
197
|
+
|
198
|
+
class Runner
|
199
|
+
include ElsToken
|
200
|
+
end
|
201
|
+
|
202
|
+
def authenticate(username,password)
|
203
|
+
Runner.authenticate(username,password,self.class.els_options)
|
204
|
+
end
|
205
|
+
|
206
|
+
def is_token_valid?(token)
|
207
|
+
Runner.is_token_valid?(token,self.class.els_options)
|
208
|
+
end
|
209
|
+
|
75
210
|
def get_token_identity(token)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
211
|
+
Runner.get_token_identity(token,self.class.els_options)
|
212
|
+
end
|
213
|
+
|
214
|
+
def get_raw_token_identity(token)
|
215
|
+
Runner.get_raw_token_identity(token,self.class.els_options)
|
82
216
|
end
|
83
217
|
|
84
|
-
# When used inside a rack environment
|
85
|
-
# will attempt to retrieve the user token
|
86
|
-
# from the session cookie and return a full
|
87
|
-
# identity
|
88
218
|
def get_identity
|
89
|
-
|
90
|
-
|
91
|
-
if is_cookie_token_valid?
|
92
|
-
get_token_identity cookies[self.class.els_options['cookie']]
|
93
|
-
else
|
94
|
-
raise "token is invalid"
|
95
|
-
end
|
96
|
-
rescue Exception => e
|
97
|
-
raise e
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def method_missing(m, *args, &block)
|
102
|
-
puts "Drop the crack pipe - There is no method called #{m}"
|
219
|
+
token = cookies[self.class.els_options['cookie']]
|
220
|
+
Runner.get_identity(token,self.class.els_options)
|
103
221
|
end
|
104
|
-
|
105
|
-
private
|
106
222
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
elsif Dir.exist? rootca
|
118
|
-
http.ca.path = rootca
|
119
|
-
else
|
120
|
-
raise "${rootca} cannot be found"
|
121
|
-
end
|
122
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
123
|
-
http.verify_depth = 5
|
223
|
+
# extract the token from a cookie
|
224
|
+
# This method expects a hash called cookies
|
225
|
+
# to be present. It will look for a cookie with
|
226
|
+
# the key of the cookie value in the config hash
|
227
|
+
def is_cookie_token_valid?
|
228
|
+
return true if self.class.els_options.has_key? 'faker'
|
229
|
+
raise "No cookies instance found" if cookies.nil?
|
230
|
+
token = cookies[self.class.els_options['cookie']]
|
231
|
+
if token.nil? || !Runner.is_token_valid?(token,self.class.els_options)
|
232
|
+
false
|
124
233
|
else
|
125
|
-
|
234
|
+
true
|
126
235
|
end
|
127
|
-
|
128
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
129
|
-
|
130
|
-
http.request(request)
|
131
236
|
end
|
132
237
|
|
133
|
-
|
134
|
-
|
238
|
+
# How about a few class methods of our own?
|
239
|
+
|
240
|
+
def self.authenticate(username,password,options)
|
241
|
+
Runner.authenticate(username,password,options)
|
135
242
|
end
|
136
|
-
|
137
|
-
def
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
id.instance_variable_set("@first_name",self.class.els_options['faker']['first_name'])
|
144
|
-
id.instance_variable_set("@uac",self.class.els_options['faker']['uac'])
|
145
|
-
id.instance_variable_set("@dn",self.class.els_options['faker']['dn'])
|
146
|
-
id.instance_variable_set("@common_name",self.class.els_options['faker']['common_name'])
|
147
|
-
id.instance_variable_set("@employee_number",self.class.els_options['faker']['employee_number'])
|
148
|
-
id.instance_variable_set("@display_name",self.class.els_options['faker']['display_name'])
|
149
|
-
id.instance_variable_set("@token_id",self.class.els_options['faker']['token_id'])
|
150
|
-
@fake_id = id
|
151
|
-
end
|
152
|
-
@fake_id
|
243
|
+
|
244
|
+
def self.is_token_valid?(token, options)
|
245
|
+
Runner.is_token_valid?(token,options)
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.get_identity(token, options)
|
249
|
+
Runner.get_identity(token,options)
|
153
250
|
end
|
154
|
-
|
155
251
|
end
|
@@ -4,12 +4,19 @@ module ElsToken
|
|
4
4
|
|
5
5
|
class ElsIdentity
|
6
6
|
attr_reader :roles, :mail, :last_name, :first_name, :uac, :dn, :common_name
|
7
|
-
attr_reader :employee_number, :display_name, :name, :token_id
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
attr_reader :employee_number, :display_name, :name, :token_id, :user_status
|
8
|
+
|
9
|
+
alias :cdid :name
|
10
|
+
|
11
|
+
# The Active Directory User Account Control contains lots of
|
12
|
+
# interesting info about the user account state. This method
|
13
|
+
# does a very simple check to see if the account is enabled
|
14
|
+
# and return either "enabled" or "disabled". There are many
|
15
|
+
# other states but I don't use them
|
16
|
+
def friendly_uac
|
17
|
+
@friendly_uac ||= (@uac.to_i & 2 == 0) ? "enabled" : "disabled"
|
11
18
|
end
|
12
|
-
|
19
|
+
|
13
20
|
def has_role?(role)
|
14
21
|
@roles.include? role
|
15
22
|
end
|
@@ -43,7 +50,6 @@ module ElsToken
|
|
43
50
|
|
44
51
|
when line =~ /name=useraccountcontrol/
|
45
52
|
self_set :uac
|
46
|
-
@uac = (uac.to_i & 2 == 0) ? "enabled" : "disabled"
|
47
53
|
|
48
54
|
when line =~ /name=givenname/
|
49
55
|
self_set :first_name
|
@@ -62,6 +68,9 @@ module ElsToken
|
|
62
68
|
|
63
69
|
when line =~ /name=displayname/
|
64
70
|
self_set :display_name
|
71
|
+
|
72
|
+
when line =~ /name=inetUserStatus/
|
73
|
+
self_set :user_status
|
65
74
|
end
|
66
75
|
end
|
67
76
|
rescue
|
data/lib/els_token/version.rb
CHANGED
data/test/dummy/Gemfile
CHANGED
@@ -1,3 +1,12 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
3
|
gem 'rails', '~> 3.2.0'
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'sqlite3'
|
7
|
+
end
|
8
|
+
|
9
|
+
gem 'coffee-rails', '~> 3.2.1'
|
10
|
+
gem 'jquery-rails'
|
11
|
+
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
12
|
+
#gem 'therubyracer'
|
data/test/dummy/Gemfile.lock
CHANGED
@@ -30,10 +30,22 @@ GEM
|
|
30
30
|
multi_json (~> 1.0)
|
31
31
|
arel (3.0.2)
|
32
32
|
builder (3.0.3)
|
33
|
+
coffee-rails (3.2.2)
|
34
|
+
coffee-script (>= 2.2.0)
|
35
|
+
railties (~> 3.2.0)
|
36
|
+
coffee-script (2.2.0)
|
37
|
+
coffee-script-source
|
38
|
+
execjs
|
39
|
+
coffee-script-source (1.3.3)
|
33
40
|
erubis (2.7.0)
|
41
|
+
execjs (1.4.0)
|
42
|
+
multi_json (~> 1.0)
|
34
43
|
hike (1.2.1)
|
35
44
|
i18n (0.6.1)
|
36
45
|
journey (1.0.4)
|
46
|
+
jquery-rails (2.1.3)
|
47
|
+
railties (>= 3.1.0, < 5.0)
|
48
|
+
thor (~> 0.14)
|
37
49
|
json (1.7.5)
|
38
50
|
mail (2.4.4)
|
39
51
|
i18n (>= 0.4.0)
|
@@ -47,7 +59,7 @@ GEM
|
|
47
59
|
rack (>= 0.4)
|
48
60
|
rack-ssl (1.3.2)
|
49
61
|
rack
|
50
|
-
rack-test (0.6.
|
62
|
+
rack-test (0.6.2)
|
51
63
|
rack (>= 1.0)
|
52
64
|
rails (3.2.8)
|
53
65
|
actionmailer (= 3.2.8)
|
@@ -71,6 +83,7 @@ GEM
|
|
71
83
|
hike (~> 1.2)
|
72
84
|
rack (~> 1.0)
|
73
85
|
tilt (~> 1.1, != 1.3.0)
|
86
|
+
sqlite3 (1.3.6)
|
74
87
|
thor (0.16.0)
|
75
88
|
tilt (1.3.3)
|
76
89
|
treetop (1.4.10)
|
@@ -82,4 +95,7 @@ PLATFORMS
|
|
82
95
|
ruby
|
83
96
|
|
84
97
|
DEPENDENCIES
|
98
|
+
coffee-rails (~> 3.2.1)
|
99
|
+
jquery-rails
|
85
100
|
rails (~> 3.2.0)
|
101
|
+
sqlite3
|