persistent_cookie_authentication_generator 0.0.1

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.
@@ -0,0 +1,67 @@
1
+ require "openssl"
2
+ require "net/smtp"
3
+
4
+ Net::SMTP.class_eval do
5
+ private
6
+ def do_start(helodomain, user, secret, authtype)
7
+ raise IOError, 'SMTP session already started' if @started
8
+ check_auth_args user, secret, authtype if user or secret
9
+
10
+ sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
11
+ @socket = Net::InternetMessageIO.new(sock)
12
+ @socket.read_timeout = 60 #@read_timeout
13
+ #@socket.debug_output = STDERR #@debug_output
14
+
15
+ check_response(critical { recv_response() })
16
+ do_helo(helodomain)
17
+
18
+ if starttls
19
+ raise 'openssl library not installed' unless defined?(OpenSSL)
20
+ ssl = OpenSSL::SSL::SSLSocket.new(sock)
21
+ ssl.sync_close = true
22
+ ssl.connect
23
+ @socket = Net::InternetMessageIO.new(ssl)
24
+ @socket.read_timeout = 60 #@read_timeout
25
+ #@socket.debug_output = STDERR #@debug_output
26
+ do_helo(helodomain)
27
+ end
28
+
29
+ authenticate user, secret, authtype if user
30
+ @started = true
31
+ ensure
32
+ unless @started
33
+ # authentication failed, cancel connection.
34
+ @socket.close if not @started and @socket and not @socket.closed?
35
+ @socket = nil
36
+ end
37
+ end
38
+
39
+ def do_helo(helodomain)
40
+ begin
41
+ if @esmtp
42
+ ehlo helodomain
43
+ else
44
+ helo helodomain
45
+ end
46
+ rescue Net::ProtocolError
47
+ if @esmtp
48
+ @esmtp = false
49
+ @error_occured = false
50
+ retry
51
+ end
52
+ raise
53
+ end
54
+ end
55
+
56
+ def starttls
57
+ getok('STARTTLS') rescue return false
58
+ return true
59
+ end
60
+
61
+ def quit
62
+ begin
63
+ getok('QUIT')
64
+ rescue EOFError, OpenSSL::SSL::SSLError
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,147 @@
1
+ require 'digest/sha1'
2
+
3
+ class User < ActiveRecord::Base
4
+
5
+ belongs_to :identity
6
+
7
+ attr_accessor :new_password
8
+
9
+ after_save '@new_password = false'
10
+ after_validation :crypt_password
11
+
12
+ validates_presence_of :login
13
+ validates_length_of :login, :within => 3..40
14
+ validates_uniqueness_of :login
15
+
16
+ validates_presence_of :email
17
+ validates_uniqueness_of :email
18
+
19
+ validates_presence_of :password, :if => :validate_password?
20
+ validates_confirmation_of :password, :if => :validate_password?
21
+ validates_length_of :password, { :minimum => 5, :if => :validate_password? }
22
+ validates_length_of :password, { :maximum => 40, :if => :validate_password? }
23
+
24
+
25
+ #initialising
26
+ def initialize(attributes = nil)
27
+ super
28
+ @new_password = false
29
+ end
30
+
31
+
32
+
33
+ #authentiacation
34
+ def self.authenticate(login, password)
35
+ userFound = find(:first, :conditions => ["login = ? AND verified = 1", login])
36
+
37
+ if userFound != nil
38
+ authenticatedUser = find(:first, :conditions => ["login = ? AND verified = 1 AND salted_password = ?", login, salted_password(userFound.salt, hashed(password)) ])
39
+ if authenticatedUser != nil
40
+ return authenticatedUser.identity_id
41
+ else
42
+ return 0
43
+ end
44
+ else
45
+ return 0
46
+ end
47
+ end
48
+
49
+
50
+
51
+ #authenticate by token
52
+ def self.authenticate_by_token(id, token)
53
+ userFound = find(:first, :conditions => ["id = ? AND security_token = ?", id, token])
54
+
55
+ if userFound.nil? or !userFound.update_verified
56
+ return false
57
+ else
58
+ return true
59
+ end
60
+ end
61
+
62
+
63
+
64
+ # update the token
65
+ def update_verified
66
+ write_attribute("verified", 1)
67
+ update_without_callbacks
68
+ end
69
+
70
+
71
+
72
+ #generate a security token
73
+ def generate_security_token(hours = nil)
74
+ if not hours.nil? or self.security_token.nil?
75
+ return new_security_token(hours)
76
+ else
77
+ return self.security_token
78
+ end
79
+ end
80
+
81
+
82
+
83
+ # changing the password
84
+ def change_password(pass, confirm = nil)
85
+ self.password = pass
86
+ self.password_confirmation = confirm.nil? ? pass : confirm
87
+ @new_password = true
88
+ end
89
+
90
+
91
+
92
+ # generate a random password
93
+ def generate_random_string(password_length)
94
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
95
+ newPassword = ""
96
+ 1.upto(password_length) { |i| newPassword << chars[rand(chars.size-1)] }
97
+ return newPassword
98
+ end
99
+
100
+
101
+
102
+ protected
103
+
104
+ attr_accessor :password, :password_confirmation
105
+
106
+
107
+ # validating the password
108
+ def validate_password?
109
+ @new_password
110
+ end
111
+
112
+
113
+
114
+ # hashing a string
115
+ def self.hashed(str)
116
+ return Digest::SHA1.hexdigest("change-me--#{str}--")[0..39]
117
+ end
118
+
119
+
120
+
121
+ # encrypting the password
122
+ def crypt_password
123
+ if @new_password
124
+ write_attribute("salt", self.class.hashed("salt-#{Time.now}"))
125
+ write_attribute("salted_password", self.class.salted_password(salt, self.class.hashed(@password)))
126
+ end
127
+ end
128
+
129
+
130
+
131
+ # security token
132
+ def new_security_token(hours = nil)
133
+ write_attribute('security_token', self.class.hashed(self.salted_password + Time.now.to_i.to_s + rand.to_s))
134
+ update_without_callbacks
135
+ return self.security_token
136
+ end
137
+
138
+
139
+
140
+ # salting the password. can i add sugar instead?
141
+ def self.salted_password(salt, hashed_password)
142
+ hashed(salt + hashed_password)
143
+ end
144
+
145
+ end
146
+
147
+
@@ -0,0 +1,22 @@
1
+ <h1>Change Password</h1>
2
+
3
+ <% if flash[:notice] %><div class="notice"><%= flash[:notice] %></div><% end %>
4
+
5
+ <% form_for(:user, :url => { :action => 'update_password' }) do |f| %>
6
+ <table>
7
+ <tr>
8
+ <td>Current Password</td>
9
+ <td><%= password_field_tag 'current_password' %></td>
10
+ </tr>
11
+ <tr>
12
+ <td>New Password</td>
13
+ <td><%= f.password_field(:password) %></td>
14
+ </tr>
15
+ <tr>
16
+ <td>New Password confirmation</td>
17
+ <td><%= f.password_field(:password_confirmation) %></td>
18
+ </tr>
19
+ </table>
20
+
21
+ <p><%= submit_tag 'Change Password' %></p>
22
+ <% end %>
@@ -0,0 +1,302 @@
1
+ class UserController < ApplicationController
2
+
3
+ before_filter :login_required, :only => [:logout, :change_password, :update_password, :edit, :update, :welcome, :show]
4
+
5
+ # login landing page
6
+ def login
7
+ end
8
+
9
+
10
+
11
+ # the login part
12
+ def user_login
13
+ resetSession
14
+ userIdentity = User.authenticate(params[:user][:login], params[:user][:password])
15
+
16
+ if userIdentity > 0
17
+ flash[:notice] = "Welcome"
18
+ setCurrentIdentity(userIdentity, PRIVATE_STATE)
19
+ setCookie(userIdentity, cookies[COOKIE_NAME])
20
+ redirect_back_or_default :action => 'show'
21
+ else
22
+ flash[:notice] = "Wrong user name or password. Please try again"
23
+ redirect_to :action => 'login'
24
+ end
25
+ end
26
+
27
+
28
+
29
+ # the logout part
30
+ def logout
31
+ resetSession
32
+ flash[:notice] = "You have logged out"
33
+ redirect_to :action => 'login'
34
+ end
35
+
36
+
37
+
38
+ # sign up page
39
+ def signup
40
+ end
41
+
42
+
43
+
44
+ # creating the user and sending the sign up email
45
+ def user_signup
46
+ #defensive programming
47
+ if params[:user] == nil
48
+ raise "null input"
49
+ end
50
+
51
+ @user = User.new(params[:user])
52
+ @user.new_password = true
53
+
54
+ #creating the identity for it
55
+ @identity = Identity.new
56
+
57
+ if !@identity.save
58
+ raise "cannot create identity"
59
+ end
60
+
61
+ @user.identity = @identity
62
+
63
+ if @user.save
64
+ key = @user.generate_security_token
65
+ url = url_for(:action => 'welcome')
66
+ url += "?user[id]=#{@user.id}&key=#{key}"
67
+
68
+ UserNotify.deliver_signup(@user, params[:user][:password], url)
69
+ flash[:notice] = "Sign up has succeeded. Please check your email for activation instructions"
70
+ redirect_to :action => 'login'
71
+ else
72
+ @identity.destroy #clears the identity as the user is not valid
73
+
74
+ if @user.errors.empty? == false
75
+ showErr(@user)
76
+ redirect_to :action => 'signup'
77
+ else
78
+ raise "Problem saving the user"
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+
85
+ # change password form
86
+ def change_password
87
+ end
88
+
89
+
90
+
91
+ # changing the password
92
+ def update_password
93
+ @user = getCurrentUser
94
+
95
+ if User.authenticate(@user.login, params[:current_password]) != 0
96
+ @user.change_password(params[:user][:password], params[:user][:password_confirmation])
97
+
98
+ if @user.save
99
+ UserNotify.deliver_change_password(@user, params[:user][:password])
100
+ flash[:notice] = "Password is changed successfully"
101
+ redirect_to :action => 'show'
102
+ else
103
+ if @user.errors.empty? == false
104
+ showErr(@user)
105
+ redirect_to :action => 'change_password'
106
+ else
107
+ raise "Problem updating the password"
108
+ end
109
+ end
110
+ else
111
+ flash[:notice] = "Your previous password is incorrect. Please try again"
112
+ redirect_to :action => 'change_password'
113
+ end
114
+ end
115
+
116
+
117
+
118
+ # forgot your pasword page
119
+ def forgot_password
120
+ end
121
+
122
+
123
+
124
+ # send the user an email with the new password
125
+ def send_new_password
126
+ # defensive programming
127
+ if params[:user] == nil
128
+ raise "null inputs"
129
+ end
130
+
131
+ @user = User.find_by_email(params[:user][:email])
132
+
133
+ if @user != nil
134
+ randomPassword = @user.generate_random_string(8)
135
+ @user.change_password(randomPassword, randomPassword)
136
+
137
+ if @user.save
138
+ UserNotify.deliver_forgot_password(@user, randomPassword)
139
+ flash[:notice] = "Email is sent successfully"
140
+ redirect_back_or_default :action => 'login'
141
+ else
142
+ raise "failed to save password changes"
143
+ end
144
+
145
+ else
146
+ flash[:notice] = "The email is not valid"
147
+ redirect_to :action => 'login', :controller => 'user'
148
+ end
149
+ end
150
+
151
+
152
+
153
+ # editing the user
154
+ def edit
155
+ @user = getCurrentUser
156
+ end
157
+
158
+
159
+
160
+ # updating the user details
161
+ def update
162
+ @user = getCurrentUser
163
+
164
+ if @user.update_attributes(params[:user])
165
+ flash[:notice] = "Update is successful"
166
+ redirect_to :action => 'show'
167
+ else
168
+ if @user.errors.empty? == false
169
+ showErr(@user)
170
+ redirect_to :action => 'edit'
171
+ else
172
+ raise "Problem saving the user."
173
+ end
174
+ end
175
+ end
176
+
177
+
178
+
179
+ # welcome screen
180
+ def welcome
181
+ # defensive programming
182
+ if params[:user] == nil
183
+ redirect_to :action => 'login'
184
+ end
185
+
186
+ @user = User.new(params[:user])
187
+
188
+ if User.authenticate_by_token(params[:user][:id], params[:key])
189
+ flash[:notice] = "Verification successful. Please Login"
190
+ redirect_to :action => 'login'
191
+ else
192
+ flash[:notice] = "Verification unsuccessful. Please try again in a moment's time"
193
+ redirect_to :action => 'login'
194
+ end
195
+ end
196
+
197
+
198
+
199
+ # the user home page
200
+ def show
201
+ @user = getCurrentUser
202
+ end
203
+
204
+
205
+ private
206
+
207
+
208
+
209
+ # showing the errors if there're
210
+ def showErr(obj)
211
+ # defensive programming
212
+ if obj == nil
213
+ raise "null inputs"
214
+ end
215
+
216
+ errMsg = String.new
217
+ obj.errors.each_full { |msg| errMsg << msg << ". " }
218
+ flash[:notice] = "Oops...There're some errors. " + errMsg
219
+ end
220
+
221
+
222
+
223
+ # sets the cookie for this identity on the browser
224
+ def setCookie(identityID, cookieValue)
225
+ if cookieValue != nil && cookieValue.length > 0
226
+ if LoginCookie.verifyIdentity(cookieValue, identityID)
227
+ newCookie = LoginCookie.regenerateCookie(cookieValue)
228
+ associateWithIdentity(newCookie, LoginCookie.getIdentity(cookieValue))
229
+ cookies[COOKIE_NAME] = { :value => newCookie, :expires => 10.years.from_now }
230
+ elsif LoginCookie.isAnonymousIdentity(cookieValue)
231
+ mergeIdentity(cookieValue, identityID)
232
+ else
233
+ newCookie = LoginCookie.generateCookie(getCurrentUser.login, nil)
234
+ associateWithIdentity(newCookie, identityID)
235
+ cookies[COOKIE_NAME] = { :value => newCookie, :expires => 10.years.from_now }
236
+ end
237
+ else
238
+ newCookie = LoginCookie.generateCookie(getCurrentUser.login, nil)
239
+ associateWithIdentity(newCookie, identityID)
240
+ cookies[COOKIE_NAME] = { :value => newCookie, :expires => 10.years.from_now }
241
+ end
242
+ end
243
+
244
+
245
+
246
+ # merge the anonymous identity to a known identity(identity which has a user)
247
+ def mergeIdentity(anonymousCookieValue, knownIdentityID)
248
+ # defensive programming
249
+ if anonymousCookieValue == nil || knownIdentityID == nil
250
+ return false
251
+ end
252
+
253
+ return false if !LoginCookie.isAnonymous(anonymousCookieValue)
254
+
255
+ loginValue = LoginCookie.getCookieLogin(anonymousCookieValue)
256
+
257
+ #getting the both anonymous user's identity and the known identity
258
+ anonymousCookie = LoginCookie.find(:first, :conditions => ["login = ?", loginValue])
259
+ anonymousIdentity = anonymousCookie.identity
260
+
261
+ knownIdentity = Identity.find(knownIdentityID)
262
+
263
+ return false if anonymousIdentity == nil || knownIdentity == nil
264
+
265
+ #transferring the cookies
266
+ anonymousIdentity.login_cookies.each { |cookie|
267
+ cookie.identity_id = knownIdentity.id
268
+ cookie.save
269
+ }
270
+
271
+ #finally send the identity to its grave
272
+ anonymousIdentity.destroy
273
+
274
+ return true
275
+ end
276
+
277
+
278
+
279
+ # associating the cookie with the identity
280
+ def associateWithIdentity(cookieValue, identityID)
281
+ #defensive programming
282
+ if identityID == nil || identityID == 0 || cookieValue == nil
283
+ raise "null inputs"
284
+ end
285
+
286
+ userIdentity = Identity.find(identityID)
287
+ cookieFound = LoginCookie.getCookieRef(cookieValue)
288
+
289
+ if userIdentity != nil && cookieFound != nil
290
+
291
+ if userIdentity.login_cookies == nil
292
+ userIdentity.login_cookies = cookieFound
293
+ else
294
+ userIdentity.login_cookies << cookieFound
295
+ end
296
+
297
+ userIdentity.save
298
+ end
299
+ end
300
+
301
+ end
302
+