Class: Auth::AuthenticationsController

Inherits:
ApplicationController
  • Object
show all
Includes:
Controllers::DeviseReturnable, Controllers::MasqueradeGuarded, CrmHelper
Defined in:
app/controllers/auth/authentications_controller.rb

Overview

== Schema Information

Table name: authentications

id :integer not null, primary key
account_id :integer
provider :string(255)
uid :string(255)
created_at :datetime not null
updated_at :datetime not null

Constant Summary

Constants included from Controllers::MasqueradeGuarded

Controllers::MasqueradeGuarded::DEFAULT_BLOCK_MESSAGE

Constants included from Controllers::DeviseReturnable

Controllers::DeviseReturnable::ALLOWED_REDIRECT_HOSTS

Instance Method Summary collapse

Methods included from CrmHelper

#alert, #array_to_list, #attr_display, #attr_display_value, #attr_displays, #attr_list_display, #audit_button, #audit_links, #audit_trail_creator_name, #bootstrap_class_for, #centered_row, #counter_badge, #counter_span, #crm_home_path, #delete_link, #duration_for_select, #dynamic_status_flow, #edit_link, #friendly_date_range, #identifiers, #modal_close_button, #modal_close_on_submit_js, #modal_dialog, #modal_dialog_body, #modal_dialog_footer, #modal_dialog_header, #multi_locale_attr_display, #navbar_user_initials, #notes_popover, #paginate_bar, #panel, #possible_events, #pretty_json_include, #pretty_json_tag, #product_line_image_row, #render_button_drop_down_options, #render_combo_drop_down, #render_material_alerts, #render_primary_combo_drop_down, #render_simple_drop_down, #render_tab_link, #render_tab_panel, #report_message_js, #simple_list_panel, #simple_panel, #simple_panel_table, #simple_panel_value, #tab_panel, #tab_should_be_open?, #text_only, #time_collection_for_select, #timezone_abbreviated, #traffic_badge_class, #truncate_array_for_display, #turbo_stream_activate_tab, #verification_badge

Methods included from Controllers::MasqueradeGuarded

block_while_masquerading, #masquerade_blocks?

Methods included from Controllers::DeviseReturnable

#check_for_devise_return_path, #devise_return_path_from_omniauth_hash, #safe_referer

Instance Method Details

#createObject

POST /authentications
POST /authentications.json



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'app/controllers/auth/authentications_controller.rb', line 41

def create
  logger.debug "authentications#create: @devise_return_path: #{@devise_return_path}"
  logger.debug "current_account: #{.inspect}"
  logger.debug "request.env['omniauth.auth']: #{request.env["omniauth.auth"].inspect}"
  logger.debug "session['devise.omniauth_data']: #{session["devise.omniauth_data"].inspect}"
  logger.debug "request.env['omniauth.origin']: #{request.env['omniauth.origin'].inspect}"
  logger.debug "request.env['omniauth.params']: #{request.env['omniauth.params'].inspect}"
  if request.env['omniauth.error']
    logger.error "OmniAuth ERROR: type=#{request.env['omniauth.error.type']} message=#{request.env['omniauth.error'].message} strategy=#{request.env['omniauth.error.strategy']&.name}"
  elsif request.env['omniauth.auth'].nil? && session['devise.omniauth_data'].nil?
    logger.error "OmniAuth callback reached create action with NO auth data. PATH_INFO=#{request.env['PATH_INFO']} params=#{request.params.except('authenticity_token').to_unsafe_h}"
  end
  @omniauth = get_omniauth_session_from_session_or_params
  if @omniauth and @omniauth['provider'] and @omniauth['uid']
    authentication = Authentication.find_by(provider: @omniauth['provider'], uid: @omniauth['uid'])
    email =  Authentication.extract_email_from_omniauth_hash(@omniauth)
    @account = Account.find_by(email: email)
    # check first that user is currently logged in
    if 
      # Linking a new OAuth identity to the masqueraded account would persist
      # past the end of the masquerade session — same threat model as
      # `destroy` (unlinking). The settings UI hides these affordances when
      # `masquerade_blocks?` is true, but a determined employee could still
      # complete an OAuth round-trip; reject before any side-effect.
      if 
        reject_action_during_masquerade!(
          'Social login changes are disabled while masquerading. Stop masquerading first.',
          
        )
        return
      end
      # check if authentication matches account, or none exists
      if (authentication and authentication. == .id) or authentication.nil?
        # add the authentication to their registed set of authentications if it doesn't exist.
        res = true
        unless authentication.present?
          .restore_authentication_token! # clear out old auth tokens
          res = .authentications.create(:provider => @omniauth['provider'], :uid => @omniauth['uid'])
        end
        if res
          # ok, added authentication to the current account
          flash[:info] = "Woohoo! #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize} authentication added."
          redirect_to (@devise_return_path || )
        else
          # couldn't create the authentication let user try to register
          session["devise.omniauth_data"] = @omniauth.except('extra')
          logger.debug "Oops! Problems with sign in: #{.errors_to_s}."
          flash[:error] = "Oops! Problems with sign in: #{.errors_to_s}. Please try again or contact us at #{self.class.helpers.raw("<a href='mailto:heatwaveteam@warmlyyours.com'>heatwaveteam@warmlyyours.com</a>")} and we'll help you out."
          redirect_to 
        end
      else
        # here we have an authentication that doesn't belong to the current account, warn and move on
        flash[:error] = "Whoops! That #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize} authentication is linked to another WarmlyYours account with e-mail: #{authentication..email}. Either sign out of your WarmlyYours account and try again, or sign out of your #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize} account and try again. Let us know if you need help with this issue at #{self.class.helpers.raw("<a href='mailto:heatwaveteam@warmlyyours.com'>heatwaveteam@warmlyyours.com</a>")}"
        redirect_to 
      end
    elsif authentication && authentication..is_employee?
      flash[:error] = "We no longer allow WarmlyYours CRM/employee accounts to sign into www.warmlyyours.com. Please try using the CRM to accomplish the task you are trying to do here. If you really want to sign in here, you will need to register a new account using a personal email or re-use one of our existing test accounts."
      redirect_to 
    elsif authentication && authentication..disabled?
      # Account linked to this social login is disabled - show error
      flash[:error] = authentication..inactive_message
      redirect_to (@devise_return_path || )
    elsif authentication
      # no current account logged in, so use the found authentication to sign in to their account.
      flash[:info] = "Awesome! Signed in through #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize}."
      (:account, authentication.)
      
      # This is now removed, but kept in for reference, 2/28/18, - Ramie
      # logger.debug "Signed in through #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize}, JWT Token is #{env['warden-jwt_auth.token']}"
      logger.debug "Signed in through #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize}"
      authentication..restore_authentication_token! # clear out old auth tokens
      redirect_to (@devise_return_path || )
    elsif @account && !@account.disabled?
      flash[:info] = "We signed you in through #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize} and added that as a social login in your account."
      @account.apply_omniauth(@omniauth)
      (:account, @account)
      
      @account.restore_authentication_token!
      redirect_to (@devise_return_path || )
    elsif @account && @account.disabled?
      flash[:error] = @account.inactive_message
      redirect_to (@devise_return_path || )
    else
      # here we are registering a new account using the authentication
      logger.debug "@context_user.id: #{@context_user.id}"
      provider_name = Authentication::PROVIDERS[@omniauth['provider']][:name].titleize

      # Mirror the customer-sessions guard: never create an OAuth account
      # on top of someone else's already-real party. If the resolved
      # @context_user has been promoted out of guest, drop the stale
      # session pointer and bounce back to sign-in.
      if oauth_register_would_clobber_existing_identity?
        msg = "[oauth-register-clobber-blocked] context_user_id=#{@context_user&.id} state=#{@context_user&.state.inspect} existing_account_id=#{@context_user&.&.id} omniauth_email=#{@omniauth.dig('user_info', 'email').inspect}"
        logger.warn msg
        ErrorReporting.warning(msg, context_user_id: @context_user&.id, action: 'oauth_register')
        session.delete(:guest_user_id)
        flash[:error] = "We could not finish signing you in with #{provider_name} because this browser is still associated with another account. Please sign in to that account or start a fresh session and try again."
        redirect_to (devise_return_path: @devise_return_path)
        return
      end

      @account = Account.new(:party_id => @context_user.id)
      @account.apply_omniauth(@omniauth)
      @account.require_password = false
      if @account.save
        logger.debug "@context_user.state: BEFORE #{@context_user.state}"
        # Only adopt OAuth identity onto a fresh guest party. For anything
        # else, keep the CRM-curated identity intact.
        if @context_user.state.to_s == 'guest'
          @context_user.email = @account.email
          @context_user.name = @account.name
          @context_user.leadify
        end
        res = @context_user.save
        logger.debug "res = @context_user.save: #{res}"
        logger.debug "@context_user.errors.full_messages: #{@context_user.errors.full_messages}"
        logger.debug "@context_user.state: #{@context_user.state}"
        track_event('Lead - Form Submitted', { leadType: 'Registration', source: "oauth_#{provider_name.downcase}" })
        flash[:info] = "Well done! You have successfully registered your WarmlyYours account using #{provider_name}. We set your name and email from #{provider_name}, but you may want to update your account contact information."
        (:account, @account)
        # This is now removed, but kept in for reference, 2/28/18, - Ramie
        # logger.debug "registered account using #{Authentication::PROVIDERS[@omniauth['provider']][:name].titleize}, JWT Token is #{env['warden-jwt_auth.token']}"
        logger.debug "registered account using #{provider_name}"
        @account.restore_authentication_token! # clear out old auth tokens
        next_path = (@devise_return_path || )
        if @context_user.name.blank? || @context_user.name.downcase.index("guest").present?
          next_path = (devise_return_path: @devise_return_path)
        end
        redirect_to next_path
      elsif (@account.email.present? and @account.errors.map{|k,v| {k => v}}.any?{|e| e[:email].to_s.downcase.index("been taken")}) or
        (@account..present? and @account.errors.map{|k,v| {k => v}}.any?{|e| e[:login].to_s.downcase.index("been taken")})
        logger.debug "@account.errors.full_messages: #{@account.errors.full_messages}"
        flash[:error] = "Errrrmmmm... Sorry! There is already another WarmlyYours account with username or e-mail: #{@account.email}. Please sign in to that account using your password or previously added authentication, then add #{provider_name} authentication from your account page."
        redirect_to (login: @account. || @account.email)
      else
        need_info = []
        need_info << 'email' unless @account.email.present?
        need_info << 'first and last name' unless @account.name.present?
        logger.debug "Problems with sign in, #{provider_name} did not provide some information, please add the following: #{need_info.join(', ')}."
        flash[:info] = "Problems with sign in, #{provider_name} did not provide some information, please add the following: #{need_info.join(', ')}."
        redirect_to (omniauth: @omniauth)
      end
    end
  else
    flash[:error] = "Well, this is embarrassing… We’re having trouble contacting provider. What's up with that? Please try again."
    ErrorReporting.warning("authentications#create could not contact omniauth provider.", @omniauth)
    redirect_to 
  end
end

#destroyObject

DELETE /authentications/1
DELETE /authentications/1.json



276
277
278
279
280
281
282
283
284
285
286
287
# File 'app/controllers/auth/authentications_controller.rb', line 276

def destroy
  if 
    @authentication = .authentications.find(params[:id])
    if .authentications.count == 1 and .encrypted_password.blank?
      flash[:error] = "Could not remove #{@authentication.provider.titleize} from your registered authentications! You would have no way to authenticate your account! Either create a password to sign in to your account or consider deleting your account."
    else
      @authentication.destroy
      flash[:info] = "Success! Removed #{Authentication::PROVIDERS[@authentication.provider][:name].titleize} from your registered authentications."
    end
  end
  redirect_back_or_to 
end

#indexObject

GET /authentications
GET /authentications.json



35
36
37
# File 'app/controllers/auth/authentications_controller.rb', line 35

def index
  @authentications = .authentications if 
end

#sign_in_employeeObject



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'app/controllers/auth/authentications_controller.rb', line 191

def 
  logger.debug "authentications#sign_in_employee: @devise_return_path: #{@devise_return_path}"
  logger.debug "current_account: #{.inspect}"
  logger.debug "request.env['omniauth.auth']: #{request.env["omniauth.auth"].inspect}"
  logger.debug "session['devise.omniauth_data']: #{session["devise.omniauth_data"].inspect}"
  logger.debug "request.env['omniauth.origin']: #{request.env['omniauth.origin'].inspect}"
  logger.debug "request.env['omniauth.params']: #{request.env['omniauth.params'].inspect}"
  logger.debug "@devise_return_path: #{@devise_return_path}"
  omniauth = request.env["omniauth.auth"] || session["devise.omniauth_data"]
  session["devise.omniauth_data"] = nil
  (redirect_to (:devise_return_path => @devise_return_path) and return) unless omniauth.present?
  authentication = Authentication.find_by(provider: omniauth['provider'], uid: omniauth['uid'])
  if authentication and omniauth['provider'] == 'google_oauth2'
    authentication.update(google_auth_access_token: omniauth['credentials']['token'])
    authentication.update(google_auth_refresh_token: omniauth['credentials']['refresh_token']) if omniauth['credentials']['refresh_token'].present?
  elsif authentication and omniauth['provider'] == 'zoom'
    Zoom::OauthService.new(account: authentication.).store_from_omniauth!(omniauth['credentials'])
  end

  # check first that user is currently logged in
  if  && .is_employee?
    if omniauth['provider'] == 'google_oauth2'
      existing_auth = .authentications.google_auth.first
      if existing_auth
        existing_auth.update(
          google_auth_access_token: omniauth['credentials']['token'],
          google_auth_refresh_token: omniauth['credentials']['refresh_token'].presence || existing_auth.google_auth_refresh_token
        )
        flash[:notice] = "Google account reconnected successfully. Calendar sync is now enabled."
      else
        .authentications.create(
          provider: omniauth['provider'],
          uid: omniauth['uid'],
          google_auth_access_token: omniauth['credentials']['token'],
          google_auth_refresh_token: omniauth['credentials']['refresh_token']
        )
        flash[:notice] = "Google account connected successfully. Calendar sync is now enabled."
      end
    elsif omniauth['provider'] == 'zoom'
      Zoom::OauthService.new(account: ).store_from_omniauth!(omniauth['credentials'])
      existing_auth = .authentications.zoom_auth.first
      unless existing_auth
        .authentications.create(provider: 'zoom', uid: omniauth['uid'])
      end
      flash[:notice] = "Zoom account connected successfully. Zoom meetings will be created automatically."
    else
      flash[:info] = "You are already signed in."
    end
    # Redirect to the return path if provided, otherwise back to referrer or home
    redirect_to (@devise_return_path || safe_referer || crm_home_path(.party))
  elsif authentication && authentication..is_employee? && authentication..disabled?
    # Employee account is disabled - show error
    flash[:error] = authentication..inactive_message
    redirect_to (devise_return_path: @devise_return_path)
  elsif authentication && authentication..is_employee?
    # no current account logged in, so use the found authentication to sign in to their account.
    (:account, authentication.)
    # This is now removed, but kept in for reference, 2/28/18, - Ramie
    # logger.debug "Signed in through WarmlyYours Google account, JWT Token is #{env['warden-jwt_auth.token']}"
    logger.debug "Signed in through WarmlyYours Google account"
    redirect_to (@devise_return_path || crm_home_path(authentication..party)), allow_other_host: true
  else
    # here we will use the e-mail on the Google warmlyyours.com account to login to the HW account
     = nil
    email = Authentication.extract_email_from_omniauth_hash(omniauth)
     = Account.find_by(email: email) if email
    if  && .is_employee? && .disabled?
      flash[:error] = .inactive_message
      redirect_to (devise_return_path: @devise_return_path)
    elsif  && .is_employee?
      (:account, )
      # This is now removed, but kept in for reference, 2/28/18, - Ramie
      # logger.debug "Signed in through WarmlyYours Google email, JWT Token is #{env['warden-jwt_auth.token']}"
      logger.debug "Signed in through WarmlyYours Google email}"
      authentication = .authentications.create(provider: omniauth['provider'], uid: omniauth['uid'])
      redirect_to (@devise_return_path || crm_home_path(.party))
    else
      flash[:error] = "Couldn't find an employee account with e-mail: #{email || 'n/a'}. Please use the google account associated with your WarmlyYours e-mail address."
      redirect_to (devise_return_path: @devise_return_path)
    end
  end
end