From: Kai Krueger Date: Sat, 27 Feb 2010 11:21:15 +0000 (+0000) Subject: merge 19889:20181 of rails_port into the openID branch X-Git-Tag: live~6330 X-Git-Url: https://git.openstreetmap.org/rails.git/commitdiff_plain/bbf30e76e4bfcd70e62fc84ecd32c5e494506e9e merge 19889:20181 of rails_port into the openID branch merge conflicts with the remember_me functionality --- bbf30e76e4bfcd70e62fc84ecd32c5e494506e9e diff --cc app/controllers/user_controller.rb index f9bbd5dd5,c181da305..97e184b59 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@@ -24,78 -24,21 +24,79 @@@ class UserController < ApplicationContr if Acl.find_by_address(request.remote_ip, :conditions => {:k => "no_account_creation"}) render :action => 'new' else - #The redirect from the OpenID provider reenters here again - #and we need to pass the parameters through to the - #open_id_authentication function a second time - if params[:open_id_complete] - openid_verify('', true) - #We have set the user.openid_url to nil beforehand. If it hasn't - #been set to a new valid openid_url, it means the openid couldn't be validated - if @user.nil? or @user.openid_url.nil? - render :action => 'new' - return - end - else - @user = User.new(params[:user]) - - @user.visible = true - @user.data_public = true - @user.description = "" if @user.description.nil? - @user.creation_ip = request.remote_ip - @user.languages = request.user_preferred_languages - #Set the openid_url to nil as for one it is used - #to check if the openid could be validated and secondly - #to not get dupplicate conflicts for an empty openid - @user.openid_url = nil - - if (!params[:user][:openid_url].nil? and params[:user][:openid_url].length > 0) ++ #The redirect from the OpenID provider reenters here again ++ #and we need to pass the parameters through to the ++ #open_id_authentication function a second time ++ if params[:open_id_complete] ++ openid_verify('', true) ++ #We have set the user.openid_url to nil beforehand. If it hasn't ++ #been set to a new valid openid_url, it means the openid couldn't be validated ++ if @user.nil? or @user.openid_url.nil? ++ render :action => 'new' ++ return ++ end ++ else + @user = User.new(params[:user]) + + @user.visible = true + @user.data_public = true + @user.description = "" if @user.description.nil? + @user.creation_ip = request.remote_ip + @user.languages = request.user_preferred_languages ++ #Set the openid_url to nil as for one it is used ++ #to check if the openid could be validated and secondly ++ #to not get dupplicate conflicts for an empty openid ++ @user.openid_url = nil ++ ++if (!params[:user][:openid_url].nil? and params[:user][:openid_url].length > 0) + if @user.pass_crypt.length == 0 + #if the password is empty, but we have a openid + #then generate a random passowrd to disable + #loging in via password + @user.pass_crypt = ActiveSupport::SecureRandom.base64(16) + @user.pass_crypt_confirmation = @user.pass_crypt + end + #Validate all of the other fields before + #redirecting to the openid provider + if !@user.valid? + render :action => 'new' + else + #TODO: Is it a problem to store the user variable with respect to password safty in the session variables? + #Store the user variable in the session for it to be accessible when redirecting back from the openid provider + session[:new_usr] = @user + begin + @norm_openid_url = OpenIdAuthentication.normalize_identifier(params[:user][:openid_url]) + rescue + flash.now[:error] = t 'user.login.openid invalid' + render :action => 'new' + return + end + #Verify that the openid provided is valid and that the user is the owner of the id + openid_verify(@norm_openid_url, true) + #openid_verify can return in two ways: + #Either it returns with a redirect to the openid provider who then freshly + #redirects back to this url if the openid is valid, or if the openid is not plausible + #and no provider for it could be found it just returns + #we want to just let the redirect through + if response.headers["Location"].nil? + render :action => 'new' + end + end + #At this point there was either an error and the page has been rendered, + #or there is a redirect to the openid provider and the rest of the method + #gets executed whenn this method gets reentered after redirecting back + #from the openid provider + return + end + end - if @user.save - flash[:notice] = t 'user.new.flash create success message' - Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer])) - redirect_to :action => 'login' - else - render :action => 'new' - end + + if @user.save + flash[:notice] = t 'user.new.flash create success message' + Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer])) + redirect_to :action => 'login' + else + render :action => 'new' + end end end @@@ -103,21 -46,9 +104,18 @@@ @title = t 'user.account.title' @tokens = @user.oauth_tokens.find :all, :conditions => 'oauth_tokens.invalidated_at is null and oauth_tokens.authorized_at is not null' - #The redirect from the OpenID provider reenters here again ++ #The redirect from the OpenID provider reenters here again + #and we need to pass the parameters through to the + #open_id_authentication function + if params[:open_id_complete] + openid_verify('', false) + @user.save + return + end + if params[:user] and params[:user][:display_name] and params[:user][:description] - if params[:user][:email] != @user.email - @user.new_email = params[:user][:email] - end - @user.display_name = params[:user][:display_name] + @user.new_email = params[:user][:new_email] if params[:user][:pass_crypt].length > 0 or params[:user][:pass_crypt_confirmation].length > 0 @user.pass_crypt = params[:user][:pass_crypt] @@@ -136,79 -69,28 +136,125 @@@ if @user.save set_locale - if params[:user][:email] == @user.new_email - flash.now[:notice] = t 'user.account.flash update success confirm needed' - Notifier.deliver_email_confirm(@user, @user.tokens.create) - else + if @user.new_email.nil? or @user.new_email.empty? flash.now[:notice] = t 'user.account.flash update success' + else + flash.now[:notice] = t 'user.account.flash update success confirm needed' + + begin + Notifier.deliver_email_confirm(@user, @user.tokens.create) + rescue + # Ignore errors sending email + end end end + - if (params[:user][:openid_url].length > 0) ++ if (params[:user][:openid_url].length > 0) + begin + @norm_openid_url = OpenIdAuthentication.normalize_identifier(params[:user][:openid_url]) + if (@norm_openid_url != @user.openid_url) + #If the OpenID has changed, we want to check that it is a valid OpenID and one + #the user has control over before saving the openID as a password equivalent for + #the user. + openid_verify(@norm_openid_url, false) + end + rescue + flash.now[:error] = t 'user.login.openid invalid' + end + end + + else + if flash[:errors] + flash[:errors].each do |attr,msg| + attr = "new_email" if attr == "email" + @user.errors.add(attr,msg) + end + end end end + def openid_specialcase_mapping(openid_url) + #Special case gmail.com, as it is pontentially a popular OpenID provider and unlike + #yahoo.com, where it works automatically, Google have hidden their OpenID endpoint + #somewhere obscure making it less userfriendly. + if (openid_url.match(/(.*)gmail.com(\/?)$/) or openid_url.match(/(.*)googlemail.com(\/?)$/) ) + return 'https://www.google.com/accounts/o8/id' + end + + return nil + end + + def openid_verify(openid_url,account_create) + authenticate_with_open_id(openid_url) do |result, identity_url| + if result.successful? + #We need to use the openid url passed back from the OpenID provider + #rather than the one supplied by the user, as these can be different. + #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url + #only once it comes back from the OpenID provider do we know the unique address for + #the user. + @user = session[:new_usr] unless @user #this is used for account creation when the user is not yet in the database + @user.openid_url = identity_url + elsif result.missing? + mapped_id = openid_specialcase_mapping(openid_url) + if mapped_id + openid_verify(mapped_id, account_create) + else + flash.now[:error] = t 'user.login.openid missing provider' + end + elsif result.invalid? + flash.now[:error] = t 'user.login.openid invalid' + else + flash.now[:error] = t 'user.login.auth failure' + end + end + end + - - def set_home - if params[:user][:home_lat] and params[:user][:home_lon] - @user.home_lat = params[:user][:home_lat].to_f - @user.home_lon = params[:user][:home_lon].to_f - if @user.save - flash[:notice] = t 'user.set_home.flash success' - redirect_to :controller => 'user', :action => 'account' ++ def open_id_authentication(openid_url) ++ #TODO: only ask for nickname and email, if we don't already have a user for that openID, in which case ++ #email and nickname are already filled out. I don't know how to do that with ruby syntax though, as we ++ #don't want to duplicate the do block ++ #On the other hand it also doesn't matter too much if we ask every time, as the OpenID provider should ++ #remember these results, and shouldn't repromt the user for these data each time. ++ authenticate_with_open_id(openid_url, :return_to => request.protocol + request.host_with_port + '/login?referer=' + params[:referer], :optional => [:nickname, :email]) do |result, identity_url, registration| ++ if result.successful? ++ #We need to use the openid url passed back from the OpenID provider ++ #rather than the one supplied by the user, as these can be different. ++ #e.g. one can simply enter yahoo.com in the login box, i.e. no user specific url ++ #only once it comes back from the OpenID provider do we know the unique address for ++ #the user. ++ user = User.find_by_openid_url(identity_url) ++ if user ++ if user.visible? and user.active? ++ session[:user] = user.id ++ session_expires_after 1.month if session[:remember] ++ else ++ user = nil ++ flash.now[:error] = t 'user.login.account not active' ++ end ++ else ++ #We don't have a user registered to this OpenID. Redirect to the create account page ++ #with username and email filled in if they have been given by the OpenID provider through ++ #the simple registration protocol ++ redirect_to :controller => 'user', :action => 'new', :nickname => registration['nickname'], :email => registration['email'], :openid => identity_url ++ end ++ else if result.missing? ++ #Try and apply some heuristics to make common cases more userfriendly ++ mapped_id = openid_specialcase_mapping(openid_url) ++ if mapped_id ++ open_id_authentication(mapped_id) ++ else ++ flash.now[:error] = t 'user.login.openid missing provider' ++ end ++ else if result.invalid? ++ flash.now[:error] = t 'user.login.openid invalid' ++ else ++ flash.now[:error] = t 'user.login.auth failure' ++ end ++ end + end + end + end + def go_public @user.data_public = true @user.save @@@ -266,40 -149,23 +313,40 @@@ # The user is logged in already, so don't show them the signup page, instead # send them to the home page redirect_to :controller => 'site', :action => 'index' if session[:user] + - @nickname = params['nickname'] ++ @nickname = params['nickname'] + @email = params['email'] + @openID = params['openid'] end def login + - #The redirect from the OpenID provider reenters here again ++ #The redirect from the OpenID provider reenters here again + #and we need to pass the parameters through to the + # open_id_authentication function + if params[:open_id_complete] + open_id_authentication('') + end + - if params[:user] and session[:user].nil? - - if !params[:user][:openid_url].nil? and !params[:user][:openid_url].empty? - email_or_display_name = params[:user][:email] - pass = params[:user][:password] - user = User.authenticate(:username => email_or_display_name, :password => pass) - if user - session[:user] = user.id - session_expires_after 1.month if params[:remember_me] - elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true) - flash.now[:error] = t 'user.login.account not active' ++ if !params[:user][:openid_url].nil? and !params[:user][:openid_url].empty? ++ session[:remember] = params[:remember_me] + open_id_authentication(params[:user][:openid_url]) else - email_or_display_name = params[:user][:email] - pass = params[:user][:password] - user = User.authenticate(:username => email_or_display_name, :password => pass) - if user - session[:user] = user.id - elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true) - flash.now[:error] = t 'user.login.account not active' - else - flash.now[:error] = t 'user.login.auth failure' - end - flash.now[:error] = t 'user.login.auth failure' -- end ++ email_or_display_name = params[:user][:email] ++ pass = params[:user][:password] ++ user = User.authenticate(:username => email_or_display_name, :password => pass) ++ if user ++ session[:user] = user.id ++ session_expires_after 1.month if params[:remember_me] ++ elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true) ++ flash.now[:error] = t 'user.login.account not active' ++ else ++ flash.now[:error] = t 'user.login.auth failure' ++ end ++ end end - + if session[:user] # The user is logged in, if the referer param exists, redirect them to that # unless they've also got a block on them, in which case redirect them to diff --cc app/models/user.rb index eb69dc031,0b8b512ee..1a4769544 --- a/app/models/user.rb +++ b/app/models/user.rb @@@ -22,11 -22,10 +22,11 @@@ class User < ActiveRecord::Bas validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password' validates_uniqueness_of :display_name, :allow_nil => true validates_uniqueness_of :email + validates_uniqueness_of :openid_url, :allow_nil => true validates_length_of :pass_crypt, :within => 8..255 validates_length_of :display_name, :within => 3..255, :allow_nil => true - validates_length_of :email, :within => 6..255 - validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i + validates_email_format_of :email + validates_email_format_of :new_email, :allow_blank => true validates_format_of :display_name, :with => /^[^\/;.,?]*$/ validates_numericality_of :home_lat, :allow_nil => true validates_numericality_of :home_lon, :allow_nil => true diff --cc app/views/user/account.html.erb index 99d0f216e,881750c36..c20f3526c --- a/app/views/user/account.html.erb +++ b/app/views/user/account.html.erb @@@ -1,39 -1,99 +1,102 @@@

<%= t 'user.account.my settings' %>

<%= error_messages_for 'user' %> - <% form_for :user, @user do |f| %> + <% form_for :user, :html => { :multipart => true } do |f| %> - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + ++ ++ ++ ++ + + + + + + + + + - + + + + - + + + + - class="nohome" <%end%> > + class="nohome" <%end%> > + + + - + + + + - + + + +
<%= t 'user.new.display name' %><%= f.text_field :display_name %>
<%= t 'user.new.email address' %><%= f.text_field :email, {:size => 50, :maxlength => 255} %> <%= t 'user.account.email never displayed publicly' %>
<%= t 'user.new.password' %><%= f.password_field :pass_crypt, {:value => '', :size => 30, :maxlength => 255} %>
<%= t 'user.new.confirm password' %><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255} %>
<%= t 'user.account.openid.openid' %><%= f.text_field :openid_url %> (<%= t 'user.account.openid.link text' %>)
<%= t 'user.account.public editing.heading' %> - <% if @user.data_public? %> - <%= t 'user.account.public editing.enabled' %> (<%= t 'user.account.public editing.enabled link text' %>) - <% else %> - <%= t 'user.account.public editing.disabled' %>(<%= t 'user.account.public editing.disabled link text' %>) - <% end %> -
<%= t 'user.new.display name' %><%= f.text_field :display_name %>
<%= t 'user.account.current email address' %><%= @user.email %> <%= t 'user.account.email never displayed publicly' %>
<%= t 'user.account.new email address' %><%= f.text_field :new_email, {:size => 50, :maxlength => 255} %> <%= t 'user.account.email never displayed publicly' %>
<%= t 'user.new.password' %><%= f.password_field :pass_crypt, {:value => '', :size => 30, :maxlength => 255} %>
<%= t 'user.new.confirm password' %><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255} %>
<%= t 'user.account.openid.openid' %><%= f.text_field :openid_url %> (<%= t 'user.account.openid.link text' %>)
<%= t 'user.account.public editing.heading' %> + <% if @user.data_public? %> + <%= t 'user.account.public editing.enabled' %> (<%= t 'user.account.public editing.enabled link text' %>) + <% else %> + <%= t 'user.account.public editing.disabled' %> (<%= t 'user.account.public editing.disabled link text' %>) + <% end %> +
<%= t 'user.account.profile description' %><%= f.text_area :description, :rows => '5', :cols => '60' %>
<%= t 'user.account.profile description' %><%= f.text_area :description, :rows => '5', :cols => '60' %>
<%= t 'user.account.preferred languages' %><%= f.text_field :languages %>
<%= t 'user.account.preferred languages' %><%= f.text_field :languages %>
+ <%= t 'user.account.image' %> + + <% if @user.image.nil? %> + <%= hidden_field_tag "image_action", "new" %> + <%= t 'user.account.new image' %>
<%= file_column_field "user", "image" %> + <% else %> + + + + + + + + + + + + + + +
<%= image_tag url_for_file_column(@user, "image") %><%= radio_button_tag "image_action", "keep", true %><%= t 'user.account.keep image' %>
<%= radio_button_tag "image_action", "delete" %><%= t 'user.account.delete image' %>
<%= radio_button_tag "image_action", "new" %><%= t 'user.account.replace image' %>
<%= file_column_field "user", "image", :onchange => "$('image_action_new').checked = true" %>
+ <% end %> +
<%= t 'user.account.home location' %><%= t 'user.account.no home location' %><%= t 'user.account.latitude' %> <%= f.text_field :home_lat, :size => 20, :id => "home_lat" %><%= t 'user.account.longitude' %><%= f.text_field :home_lon, :size => 20, :id => "home_lon" %>
<%= t 'user.account.home location' %><%= t 'user.account.no home location' %><%= t 'user.account.latitude' %> <%= f.text_field :home_lat, :size => 20, :id => "home_lat" %><%= t 'user.account.longitude' %><%= f.text_field :home_lon, :size => 20, :id => "home_lon" %>
-

<%= t 'user.account.update home location on click' %> checked="checked" <% end %> id="updatehome" />

-
-
+

<%= t 'user.account.update home location on click' %> checked="checked" <% end %> id="updatehome" />

+
+

<%= submit_tag t('user.account.save changes button') %>

<%= submit_tag t('user.account.save changes button') %>
-
- <% end %> <%= render :partial => 'friend_map' %> diff --cc app/views/user/login.html.erb index 16d820b69,9ff100079..269bbc0cc --- a/app/views/user/login.html.erb +++ b/app/views/user/login.html.erb @@@ -6,16 -6,9 +6,12 @@@ <%= hidden_field_tag('referer', h(params[:referer])) %> -- - - - - ++ ++ ++ + - - - - - - ++ + - ++
<%= t 'user.login.email or username' %><%= text_field('user', 'email',{:size => 28, :maxlength => 255, :tabindex => 1}) %>
<%= t 'user.login.password' %><%= password_field('user', 'password',{:size => 28, :maxlength => 255, :tabindex => 2}) %> (<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)
 
<%= submit_tag t('user.login.login_button'), :tabindex => 3 %>

<%= t 'user.login.alternatively' %>

<%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %>
<%= t 'user.login.password' %><%= password_field('user', 'password',{:size => 28, :maxlength => 255, :tabindex => 2}) %> (<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)

<%= t 'user.login.alternatively' %>

<%= t 'user.login.openid' %><%= text_field('user', 'openid_url',{:size => 28, :maxlength => 255, :tabindex => 3}) %> (<%= t 'user.account.openid.link text' %>)
<%= t 'user.login.openid description' %>         (<%= t 'user.account.openid.link text' %>)
<%= t 'user.login.openid' %><%= text_field('user', 'openid_url',{:size => 28, :maxlength => 255, :tabindex => 3}) %>
 
<%= submit_tag t('user.login.login_button'), :tabindex => 3 %>
 
 
<%= submit_tag t('user.login.login_button'), :tabindex => 3 %>
<%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %><%= submit_tag t('user.login.login_button'), :tabindex => 3 %>
<% end %> diff --cc config/locales/en.yml index 58fca9498,e75cc2206..b358cf8d3 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@@ -1456,11 -1445,9 +1452,13 @@@ en account: title: "Edit account" my settings: My settings + current email address: "Current Email Address:" + new email address: "New Email Address:" email never displayed publicly: "(never displayed publicly)" + openid: + openid: "OpenID:" + link: "http://wiki.openstreetmap.org/wiki/OpenID" + link text: "what is this?" public editing: heading: "Public editing:" enabled: "Enabled. Not anonymous and can edit data."