Description:
add authentication by CU-CAS from p' krerk
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r396:4b88edeab117 - - 1 file changed: 28 inserted, 3 deleted

@@ -1,189 +1,214
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 + require 'json'
3
4
4 class User < ActiveRecord::Base
5 class User < ActiveRecord::Base
5
6
6 has_and_belongs_to_many :roles
7 has_and_belongs_to_many :roles
7
8
8 has_many :test_requests, :order => "submitted_at DESC"
9 has_many :test_requests, :order => "submitted_at DESC"
9
10
10 has_many :messages,
11 has_many :messages,
11 :class_name => "Message",
12 :class_name => "Message",
12 :foreign_key => "sender_id",
13 :foreign_key => "sender_id",
13 :order => 'created_at DESC'
14 :order => 'created_at DESC'
14
15
15 has_many :replied_messages,
16 has_many :replied_messages,
16 :class_name => "Message",
17 :class_name => "Message",
17 :foreign_key => "receiver_id",
18 :foreign_key => "receiver_id",
18 :order => 'created_at DESC'
19 :order => 'created_at DESC'
19
20
20 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
21
22
22 belongs_to :site
23 belongs_to :site
23 belongs_to :country
24 belongs_to :country
24
25
25 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
26 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
26
27
27 scope :activated_users, :conditions => {:activated => true}
28 scope :activated_users, :conditions => {:activated => true}
28
29
29 validates_presence_of :login
30 validates_presence_of :login
30 validates_uniqueness_of :login
31 validates_uniqueness_of :login
31 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
32 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
32 validates_length_of :login, :within => 3..30
33 validates_length_of :login, :within => 3..30
33
34
34 validates_presence_of :full_name
35 validates_presence_of :full_name
35 validates_length_of :full_name, :minimum => 1
36 validates_length_of :full_name, :minimum => 1
36
37
37 validates_presence_of :password, :if => :password_required?
38 validates_presence_of :password, :if => :password_required?
38 validates_length_of :password, :within => 4..20, :if => :password_required?
39 validates_length_of :password, :within => 4..20, :if => :password_required?
39 validates_confirmation_of :password, :if => :password_required?
40 validates_confirmation_of :password, :if => :password_required?
40
41
41 validates_format_of :email,
42 validates_format_of :email,
42 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
43 :if => :email_validation?
44 :if => :email_validation?
44 validate :uniqueness_of_email_from_activated_users,
45 validate :uniqueness_of_email_from_activated_users,
45 :if => :email_validation?
46 :if => :email_validation?
46 validate :enough_time_interval_between_same_email_registrations,
47 validate :enough_time_interval_between_same_email_registrations,
47 :if => :email_validation?
48 :if => :email_validation?
48
49
49 # these are for ytopc
50 # these are for ytopc
50 # disable for now
51 # disable for now
51 #validates_presence_of :province
52 #validates_presence_of :province
52
53
53 attr_accessor :password
54 attr_accessor :password
54
55
55 before_save :encrypt_new_password
56 before_save :encrypt_new_password
56 before_save :assign_default_site
57 before_save :assign_default_site
57 before_save :assign_default_contest
58 before_save :assign_default_contest
58
59
59 # this is for will_paginate
60 # this is for will_paginate
60 cattr_reader :per_page
61 cattr_reader :per_page
61 @@per_page = 50
62 @@per_page = 50
62
63
63 def self.authenticate(login, password)
64 def self.authenticate(login, password)
64 user = find_by_login(login)
65 user = find_by_login(login)
65 - return user if user && user.authenticated?(password)
66 + if user
66 - if user && user.authenticated_by_pop3?(password)
67 + return user if user.authenticated?(password)
68 + if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
67 user.password = password
69 user.password = password
68 user.save
70 user.save
69 return user
71 return user
70 end
72 end
71 end
73 end
74 + end
72
75
73 def authenticated?(password)
76 def authenticated?(password)
74 if self.activated
77 if self.activated
75 hashed_password == User.encrypt(password,self.salt)
78 hashed_password == User.encrypt(password,self.salt)
76 else
79 else
77 false
80 false
78 end
81 end
79 end
82 end
80
83
81 def authenticated_by_pop3?(password)
84 def authenticated_by_pop3?(password)
82 Net::POP3.enable_ssl
85 Net::POP3.enable_ssl
83 pop = Net::POP3.new('pops.it.chula.ac.th')
86 pop = Net::POP3.new('pops.it.chula.ac.th')
84 authen = true
87 authen = true
85 begin
88 begin
86 - pop.start(login, password) # (1)
89 + pop.start(login, password)
87 pop.finish
90 pop.finish
88 return true
91 return true
89 rescue
92 rescue
90 return false
93 return false
91 end
94 end
92 end
95 end
93
96
97 + def authenticated_by_cucas?(password)
98 + url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
99 + appid = '41508763e340d5858c00f8c1a0f5a2bb'
100 + appsecret ='d9cbb5863091dbe186fded85722a1e31'
101 + post_args = {
102 + 'appid' => appid,
103 + 'appsecret' => appsecret,
104 + 'username' => login,
105 + 'password' => password
106 + }
107 +
108 + #simple call
109 + begin
110 + resp = Net::HTTP.post_form(url, post_args)
111 + result = JSON.parse resp.body
112 + return true if result["type"] == "beanStudent"
113 + rescue
114 + return false
115 + end
116 + return false
117 + end
118 +
94 def admin?
119 def admin?
95 self.roles.detect {|r| r.name == 'admin' }
120 self.roles.detect {|r| r.name == 'admin' }
96 end
121 end
97
122
98 def email_for_editing
123 def email_for_editing
99 if self.email==nil
124 if self.email==nil
100 "(unknown)"
125 "(unknown)"
101 elsif self.email==''
126 elsif self.email==''
102 "(blank)"
127 "(blank)"
103 else
128 else
104 self.email
129 self.email
105 end
130 end
106 end
131 end
107
132
108 def email_for_editing=(e)
133 def email_for_editing=(e)
109 self.email=e
134 self.email=e
110 end
135 end
111
136
112 def alias_for_editing
137 def alias_for_editing
113 if self.alias==nil
138 if self.alias==nil
114 "(unknown)"
139 "(unknown)"
115 elsif self.alias==''
140 elsif self.alias==''
116 "(blank)"
141 "(blank)"
117 else
142 else
118 self.alias
143 self.alias
119 end
144 end
120 end
145 end
121
146
122 def alias_for_editing=(e)
147 def alias_for_editing=(e)
123 self.alias=e
148 self.alias=e
124 end
149 end
125
150
126 def activation_key
151 def activation_key
127 if self.hashed_password==nil
152 if self.hashed_password==nil
128 encrypt_new_password
153 encrypt_new_password
129 end
154 end
130 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
155 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
131 end
156 end
132
157
133 def verify_activation_key(key)
158 def verify_activation_key(key)
134 key == activation_key
159 key == activation_key
135 end
160 end
136
161
137 def self.random_password(length=5)
162 def self.random_password(length=5)
138 chars = 'abcdefghjkmnopqrstuvwxyz'
163 chars = 'abcdefghjkmnopqrstuvwxyz'
139 password = ''
164 password = ''
140 length.times { password << chars[rand(chars.length - 1)] }
165 length.times { password << chars[rand(chars.length - 1)] }
141 password
166 password
142 end
167 end
143
168
144 def self.find_non_admin_with_prefix(prefix='')
169 def self.find_non_admin_with_prefix(prefix='')
145 users = User.find(:all)
170 users = User.find(:all)
146 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
171 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
147 end
172 end
148
173
149 # Contest information
174 # Contest information
150
175
151 def self.find_users_with_no_contest()
176 def self.find_users_with_no_contest()
152 users = User.find(:all)
177 users = User.find(:all)
153 return users.find_all { |u| u.contests.length == 0 }
178 return users.find_all { |u| u.contests.length == 0 }
154 end
179 end
155
180
156
181
157 def contest_time_left
182 def contest_time_left
158 if GraderConfiguration.contest_mode?
183 if GraderConfiguration.contest_mode?
159 return nil if site==nil
184 return nil if site==nil
160 return site.time_left
185 return site.time_left
161 elsif GraderConfiguration.indv_contest_mode?
186 elsif GraderConfiguration.indv_contest_mode?
162 time_limit = GraderConfiguration.contest_time_limit
187 time_limit = GraderConfiguration.contest_time_limit
163 if time_limit == nil
188 if time_limit == nil
164 return nil
189 return nil
165 end
190 end
166 if contest_stat==nil or contest_stat.started_at==nil
191 if contest_stat==nil or contest_stat.started_at==nil
167 return (Time.now.gmtime + time_limit) - Time.now.gmtime
192 return (Time.now.gmtime + time_limit) - Time.now.gmtime
168 else
193 else
169 finish_time = contest_stat.started_at + time_limit
194 finish_time = contest_stat.started_at + time_limit
170 current_time = Time.now.gmtime
195 current_time = Time.now.gmtime
171 if current_time > finish_time
196 if current_time > finish_time
172 return 0
197 return 0
173 else
198 else
174 return finish_time - current_time
199 return finish_time - current_time
175 end
200 end
176 end
201 end
177 else
202 else
178 return nil
203 return nil
179 end
204 end
180 end
205 end
181
206
182 def contest_finished?
207 def contest_finished?
183 if GraderConfiguration.contest_mode?
208 if GraderConfiguration.contest_mode?
184 return false if site==nil
209 return false if site==nil
185 return site.finished?
210 return site.finished?
186 elsif GraderConfiguration.indv_contest_mode?
211 elsif GraderConfiguration.indv_contest_mode?
187 return false if self.contest_stat(true)==nil
212 return false if self.contest_stat(true)==nil
188 return contest_time_left == 0
213 return contest_time_left == 0
189 else
214 else
You need to be logged in to leave comments. Login now