Passed
Push — master ( 6bc43d...2da2ee )
by Ahmad
07:04
created

SessionsController   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 244
Duplicated Lines 0.41 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
dl 1
loc 244
rs 5.5199
c 4
b 0
f 0
wmc 56

17 Methods

Rating   Name   Duplication   Size   Complexity  
A ldap_signin() 0 2 1
A new() 0 12 3
A current_provider() 0 3 2
A session_params() 0 3 1
C create() 0 34 10
A check_user_signup_allowed() 0 3 2
A signin() 0 15 3
A check_user_exists() 0 3 1
A destroy() 0 4 1
A switch_account_to_local() 0 12 2
F process_signin() 1 42 14
A one_provider() 0 4 1
A passes_invite_reqs() 0 6 2
A switch_account_to_social() 0 8 1
B ldap() 0 27 6
A check_auth_deleted() 0 3 1
A check_user_deleted() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like SessionsController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# frozen_string_literal: true
2
3
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
4
#
5
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
6
#
7
# This program is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU Lesser General Public License as published by the Free Software
9
# Foundation; either version 3.0 of the License, or (at your option) any later
10
# version.
11
#
12
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
15
#
16
# You should have received a copy of the GNU Lesser General Public License along
17
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
18
19
class SessionsController < ApplicationController
20
  include Authenticator
21
  include Registrar
22
  include Emailer
23
  include LdapAuthenticator
24
25
  skip_before_action :verify_authenticity_token, only: [:omniauth, :fail]
26
  before_action :check_user_signup_allowed, only: [:new]
27
  before_action :ensure_unauthenticated_except_twitter, only: [:new, :signin, :ldap_signin]
28
29
  # GET /signin
30
  def signin
31
    check_if_twitter_account
32
33
    @providers = configured_providers
34
35
    if one_provider
36
      provider_path = if Rails.configuration.omniauth_ldap
37
        ldap_signin_path
38
      else
39
        "#{Rails.configuration.relative_url_root}/auth/#{@providers.first}"
40
      end
41
42
      return redirect_to provider_path
43
    end
44
  end
45
46
  # GET /ldap_signin
47
  def ldap_signin
48
  end
49
50
  # GET /signup
51
  def new
52
    # Check if the user needs to be invited
53
    if invite_registration
54
      redirect_to root_path, flash: { alert: I18n.t("registration.invite.no_invite") } unless params[:invite_token]
55
56
      session[:invite_token] = params[:invite_token]
57
    end
58
59
    check_if_twitter_account(true)
60
61
    @user = User.new
62
  end
63
64
  # POST /users/login
65
  def create
66
    logger.info "Support: #{session_params[:email]} is attempting to login."
67
68
    user = User.include_deleted.find_by(email: session_params[:email])
69
70
    is_super_admin = user&.has_role? :super_admin
71
72
    # Scope user to domain if the user is not a super admin
73
    user = User.include_deleted.find_by(email: session_params[:email], provider: @user_domain) unless is_super_admin
74
75
    # Check user with that email exists
76
    return redirect_to(signin_path, alert: I18n.t("invalid_credentials")) unless user
77
78
    # Check if authenticators have switched
79
    return switch_account_to_local(user) if !is_super_admin && auth_changed_to_local?(user)
80
81
    # Check correct password was entered
82
    return redirect_to(signin_path, alert: I18n.t("invalid_credentials")) unless user.try(:authenticate,
83
      session_params[:password])
84
    # Check that the user is not deleted
85
    return redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") } if user.deleted?
86
87
    unless is_super_admin
88
      # Check that the user is a Greenlight account
89
      return redirect_to(root_path, alert: I18n.t("invalid_login_method")) unless user.greenlight_account?
90
      # Check that the user has verified their account
91
      unless user.activated?
92
        user.create_activation_token
93
        return redirect_to(account_activation_path(token: user.activation_token))
94
      end
95
    end
96
97
    login(user)
98
  end
99
100
  # GET /users/logout
101
  def destroy
102
    logout
103
    redirect_to root_path
104
  end
105
106
  # GET/POST /auth/:provider/callback
107
  def omniauth
108
    @auth = request.env['omniauth.auth']
109
110
    begin
111
      process_signin
112
    rescue => e
113
      logger.error "Error authenticating via omniauth: #{e}"
114
      omniauth_fail
115
    end
116
  end
117
118
  # POST /auth/failure
119
  def omniauth_fail
120
    if params[:message].nil?
121
      redirect_to root_path, alert: I18n.t("omniauth_error")
122
    else
123
      redirect_to root_path, alert: I18n.t("omniauth_specific_error", error: params["message"])
124
    end
125
  end
126
127
  # GET /auth/ldap
128
  def ldap
129
    ldap_config = {}
130
    ldap_config[:host] = ENV['LDAP_SERVER']
131
    ldap_config[:port] = ENV['LDAP_PORT'].to_i != 0 ? ENV['LDAP_PORT'].to_i : 389
132
    ldap_config[:bind_dn] = ENV['LDAP_BIND_DN']
133
    ldap_config[:password] = ENV['LDAP_PASSWORD']
134
    ldap_config[:encryption] = if ENV['LDAP_METHOD'] == 'ssl'
135
                                    'simple_tls'
136
                                elsif ENV['LDAP_METHOD'] == 'tls'
137
                                    'start_tls'
138
                                end
139
    ldap_config[:base] = ENV['LDAP_BASE']
140
    ldap_config[:uid] = ENV['LDAP_UID']
141
142
    result = send_ldap_request(params[:session], ldap_config)
143
144
    return redirect_to(ldap_signin_path, alert: I18n.t("invalid_credentials")) unless result
145
146
    @auth = parse_auth(result.first, ENV['LDAP_ROLE_FIELD'])
147
148
    begin
149
      process_signin
150
    rescue => e
151
      logger.error "Support: Error authenticating via omniauth: #{e}"
152
      omniauth_fail
153
    end
154
  end
155
156
  private
157
158
  # Verify that GreenLight is configured to allow user signup.
159
  def check_user_signup_allowed
160
    redirect_to root_path unless Rails.configuration.allow_user_signup
161
  end
162
163
  def session_params
164
    params.require(:session).permit(:email, :password)
165
  end
166
167
  def one_provider
168
    (!allow_user_signup? || !allow_greenlight_accounts?) && @providers.count == 1 &&
169
      !Rails.configuration.loadbalanced_configuration
170
  end
171
172
  def check_user_exists
173
    User.exists?(social_uid: @auth['uid'], provider: current_provider)
174
  end
175
176
  def check_user_deleted(email)
177
    User.deleted.exists?(email: email, provider: @user_domain)
178
  end
179
180
  def check_auth_deleted
181
    User.deleted.exists?(social_uid: @auth['uid'], provider: current_provider)
182
  end
183
184
  def current_provider
185
    @auth['provider'] == "bn_launcher" ? @auth['info']['customer'] : @auth['provider']
186
  end
187
188
  # Check if the user already exists, if not then check for invitation
189
  def passes_invite_reqs
190
    return true if @user_exists
191
192
    invitation = check_user_invited("", session[:invite_token], @user_domain)
193
    invitation[:present]
194
  end
195
196
  def process_signin
197
    @user_exists = check_user_exists
198
199
    if !@user_exists && @auth['provider'] == "twitter"
200
      return redirect_to root_path, flash: { alert: I18n.t("registration.deprecated.twitter_signup") }
201
    end
202
203
    # Check if user is deleted
204
    return redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") } if check_auth_deleted
205
206
    # If using invitation registration method, make sure user is invited
207 View Code Duplication
    return redirect_to root_path, flash: { alert: I18n.t("registration.invite.no_invite") } unless passes_invite_reqs
208
209
    # Switch the user to a social account if they exist under the same email with no social uid
210
    switch_account_to_social if !@user_exists && auth_changed_to_social?(@auth['info']['email'])
211
212
    user = User.from_omniauth(@auth)
213
214
    logger.info "Support: Auth user #{user.email} is attempting to login."
215
216
    # Add pending role if approval method and is a new user
217
    if approval_registration && !@user_exists
218
      user.add_role :pending
219
220
      # Inform admins that a user signed up if emails are turned on
221
      send_approval_user_signup_email(user)
222
223
      return redirect_to root_path, flash: { success: I18n.t("registration.approval.signup") }
224
    end
225
226
    send_invite_user_signup_email(user) if invite_registration && !@user_exists
227
228
    login(user)
229
230
    if @auth['provider'] == "twitter"
231
      flash[:alert] = if allow_user_signup? && allow_greenlight_accounts?
232
        I18n.t("registration.deprecated.twitter_signin", link: signup_path(old_twitter_user_id: user.id))
233
      else
234
        I18n.t("registration.deprecated.twitter_signin", link: signin_path(old_twitter_user_id: user.id))
235
      end
236
    end
237
  end
238
239
  # Send the user a password reset email to allow them to set their password
240
  def switch_account_to_local(user)
241
    logger.info "Switching social account to local account for #{user.uid}"
242
243
    # Send the user a reset password email
244
    user.create_reset_digest
245
    send_password_reset_email(user)
246
247
    # Overwrite the flash with a more descriptive message if successful
248
    flash[:success] = I18n.t("reset_password.auth_change") if flash[:success].present?
249
250
    redirect_to signin_path
251
  end
252
253
  # Set the user's social id to the new id being passed
254
  def switch_account_to_social
255
    user = User.find_by(email: @auth['info']['email'], provider: @user_domain, social_uid: nil)
256
257
    logger.info "Switching account to social account for #{user.uid}"
258
259
    # Set the user's social id to the one being returned from auth
260
    user.update_attribute(:social_uid, @auth['uid'])
261
  end
262
end
263