storing the ip if one user is logged in from different machine
[opensuse:yast-web-client.git] / webclient / app / models / account.rb
1 #--
2 # Webyast Webclient framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19
20 require 'uri'
21 require 'digest/sha1'
22 require 'yast/service_resource'
23
24 class Account < ActiveRecord::Base
25   # Virtual attribute for the unencrypted password
26   attr_accessor :password
27
28   validates_presence_of     :login
29   validates_presence_of     :password,                   :if => :password_required?
30   validates_length_of       :password, :within => 1..40, :if => :password_required?
31   validates_confirmation_of :password,                   :if => :password_required?
32   validates_length_of       :login,    :within => 1..40
33   validates_uniqueness_of   :login, :case_sensitive => false
34   before_save :encrypt_password
35   
36   # prevents a user from submitting a crafted form that bypasses activation
37   # anything else you want your user to change should be added here.
38   attr_accessible :login, :password
39
40   # Authenticates a user by their login name and unencrypted password to host.
41   # Returns pair of [ account, token ]
42   #
43   # Will raise unless uri is a valid uri or if target host is blocked by
44   # failed attempt to login
45   #
46   def self.authenticate(login, passwd, uri_s, remote_ip)
47     # host is just a hostname, and we want to set the
48     # HTTP client REST proxy URL to that host, so we need
49     # to add http
50     #
51     # in the future, if we use other protocols via a client
52     # proxy, we need to set the right url there too
53
54     # Ensure that we really have a http/https uri
55     uri = URI.parse(uri_s.to_s)
56     
57     unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
58       raise "service should be a http or https URI"
59     end
60
61     # set default site url for all YaST service based resources
62     YaST::ServiceResource::Session.site = uri
63     YaST::ServiceResource::Session.login = login
64         
65     YaST::ServiceResource::Base.password = ""
66     YaST::ServiceResource::Session.auth_token = ""
67     
68     # the above will obsolete this
69     YaST::ServiceResource::Base.site = uri
70     # create a login resource
71     ret = YaST::ServiceResource::Login.create(:login => login, :password =>passwd, :remember_me => true, :ip => remote_ip)
72
73     # this would log the password!
74     # logger.debug ret.inspect
75     if (ret and ret.attributes["login"] == "granted")
76       @password = passwd
77       acc = find_by_login(login)
78       if !acc
79         acc = Account.new
80         acc.login = login
81       end
82       @password = passwd
83       acc.password = passwd
84       acc.save
85       Rails.logger.info "Authenticate Successful for rest-server ID #{ret.attributes["auth_token"].attributes["value"].inspect}"
86       YaST::ServiceResource::Base.password = ret.attributes["auth_token"].attributes["value"]
87       YaST::ServiceResource::Session.auth_token = ret.attributes["auth_token"].attributes["value"]
88
89       return acc, ret.attributes["auth_token"].attributes["value"], ret.attributes["auth_token"].attributes["expires"]
90     elsif (ret && ret.attributes["login"] == "blocked")
91       raise BlockedService.new(ret.attributes["remain"])
92     else
93       Rails.logger.error "Authenticate Failure"
94       return nil, nil
95     end
96   end
97
98   class BlockedService < RuntimeError
99     attr_accessor :time
100
101     def initialize(time)
102       @time = time
103     end
104   end
105
106   # Encrypts some data with the salt.
107   def self.encrypt(data, salt)
108     Digest::SHA1.hexdigest("--#{salt}--#{data}--")
109   end
110
111   # Encrypts the data with the user salt
112   def encrypt(data)
113     self.class.encrypt(data, salt)
114   end
115
116   def remember_token?
117     remember_token_expires_at && Time.now.utc < remember_token_expires_at 
118   end
119
120   # These create and unset the fields required for remembering users between browser closes
121   def remember_me
122 #    remember_me_for 2.weeks
123     remember_me_for 1.days
124   end
125
126   def remember_me_for(time)
127     remember_me_until time.from_now.utc
128   end
129
130   def remember_me_until(time)
131     self.remember_token_expires_at = time
132     self.remember_token            = encrypt("#{login}--#{remember_token_expires_at}")
133     save(false)
134   end
135
136   def forget_me
137     self.remember_token_expires_at = nil
138     self.remember_token            = nil
139
140     save(false)
141   end
142
143   protected
144     # before filter 
145     def encrypt_password
146       return if password.blank?
147       self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
148     end
149       
150     def password_required?
151       !password.blank?
152     end
153
154 end