diff --git a/Gemfile b/Gemfile index a79eeead..4a19fefb 100644 --- a/Gemfile +++ b/Gemfile @@ -47,6 +47,7 @@ gem 'bcrypt', '~> 3.1.7' gem 'omniauth' gem 'omniauth-twitter' gem 'omniauth-google-oauth2' +gem 'omniauth-ldap' gem 'omniauth-bn-launcher', '~> 0.1.0' # BigBlueButton API wrapper. diff --git a/Gemfile.lock b/Gemfile.lock index 0bdf6cc1..21744073 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,6 +111,7 @@ GEM multi_json (1.13.1) multi_xml (0.6.0) multipart-post (2.0.0) + net-ldap (0.16.1) nio4r (2.3.1) nokogiri (1.8.3) mini_portile2 (~> 2.3.0) @@ -131,6 +132,11 @@ GEM jwt (>= 1.5) omniauth (>= 1.1.1) omniauth-oauth2 (>= 1.5) + omniauth-ldap (2.0.0) + net-ldap (~> 0.16) + omniauth (~> 1.8.1) + pyu-ruby-sasl (~> 0.0.3.3) + rubyntlm (~> 0.6.2) omniauth-oauth (1.1.0) oauth omniauth (~> 1.0) @@ -147,6 +153,7 @@ GEM popper_js (1.12.9) powerpack (0.1.2) puma (3.11.4) + pyu-ruby-sasl (0.0.3.3) rack (2.0.5) rack-test (0.6.3) rack (>= 1.0) @@ -210,6 +217,7 @@ GEM ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-progressbar (1.9.0) + rubyntlm (0.6.2) sass (3.5.6) sass-listen (~> 4.0.0) sass-listen (4.0.0) @@ -282,6 +290,7 @@ DEPENDENCIES omniauth omniauth-bn-launcher (~> 0.1.0) omniauth-google-oauth2 + omniauth-ldap omniauth-twitter pg (~> 0.18) puma (~> 3.0) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 1a5a5f3e..ae105243 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class SessionsController < ApplicationController + skip_before_action :verify_authenticity_token, only: [:omniauth, :fail] + # GET /users/logout def destroy logout @@ -13,7 +15,7 @@ class SessionsController < ApplicationController if user.try(:authenticate, session_params[:password]) login(user) else - redirect_to root_path, notice: I18n.t("login_failed") + redirect_to root_path, notice: I18n.t("invalid_credentials") end end @@ -28,7 +30,7 @@ class SessionsController < ApplicationController # POST /auth/failure def fail - redirect_to root_path + redirect_to root_path, notice: I18n.t(params[:message], default: I18n.t("omniauth_error")) end private diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4795f423..85a8a4fa 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -10,6 +10,11 @@ module ApplicationHelper end end + # Determines which providers can show a login button in the login modal. + def iconset_providers + configured_providers & [:google, :twitter] + end + # Generates the login URL for a specific provider. def omniauth_login_url(provider) "#{Rails.configuration.relative_url_root}/auth/#{provider}" diff --git a/app/models/user.rb b/app/models/user.rb index c2572e15..679306de 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,10 +25,10 @@ class User < ApplicationRecord # Provider is the customer name if in loadbalanced config mode provider = auth['provider'] == "bn_launcher" ? auth['info']['customer'] : auth['provider'] find_or_initialize_by(social_uid: auth['uid'], provider: provider).tap do |u| - u.name = send("#{auth['provider']}_name", auth) unless u.name - u.username = send("#{auth['provider']}_username", auth) unless u.username - u.email = send("#{auth['provider']}_email", auth) - u.image = send("#{auth['provider']}_image", auth) + u.name = auth_name(auth) unless u.name + u.username = auth_username(auth) unless u.username + u.email = auth_email(auth) + u.image = auth_image(auth) u.save! end end @@ -36,52 +36,32 @@ class User < ApplicationRecord private # Provider attributes. - def twitter_name(auth) + def auth_name(auth) auth['info']['name'] end - def twitter_username(auth) - auth['info']['nickname'] + def auth_username(auth) + case auth['provider'] + when :google + auth['info']['email'].split('@').first + when :bn_launcher + auth['info']['username'] + else + auth['info']['nickname'] + end end - def twitter_email(auth) + def auth_email(auth) auth['info']['email'] end - def twitter_image(auth) - auth['info']['image'].gsub("http", "https").gsub("_normal", "") - end - - def google_name(auth) - auth['info']['name'] - end - - def google_username(auth) - auth['info']['email'].split('@').first - end - - def google_email(auth) - auth['info']['email'] - end - - def google_image(auth) - auth['info']['image'] - end - - def bn_launcher_name(auth) - auth['info']['name'] - end - - def bn_launcher_username(auth) - auth['info']['username'] - end - - def bn_launcher_email(auth) - auth['info']['email'] - end - - def bn_launcher_image(auth) - auth['info']['image'] + def auth_image(auth) + case auth['provider'] + when :twitter + auth['info']['image'].gsub("http", "https").gsub("_normal", "") + else + auth['info']['image'] + end end end diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb index 2c535060..a11b4fa9 100644 --- a/app/views/shared/_header.html.erb +++ b/app/views/shared/_header.html.erb @@ -30,7 +30,7 @@ <%= t("header.dropdown.settings") %> <% end %> - + <%= t("header.dropdown.help") %> <%= link_to logout_path, class: "dropdown-item" do %> @@ -39,9 +39,11 @@ <% else %> - <% if Rails.configuration.omniauth_bn_launcher && !current_user %> - <%= link_to t("login"), "#{Rails.configuration.relative_url_root}/auth/bn_launcher", :class => "btn btn-pill btn-outline-primary mx-2" %> - <% else %> + <% if Rails.configuration.omniauth_bn_launcher %> + <%= link_to t("login"), omniauth_login_url(:bn_launcher), :class => "btn btn-pill btn-outline-primary mx-2" %> + <% elsif Rails.configuration.omniauth_ldap %> + <%= link_to t("login"), omniauth_login_url(:ldap), :class => "btn btn-pill btn-outline-primary mx-2" %> + <% else %> <%= link_to t("login"), "#loginModal", :class => "btn btn-pill btn-outline-primary mx-2", "data-toggle": "modal" %> <% end %> diff --git a/app/views/shared/modals/_login_modal.html.erb b/app/views/shared/modals/_login_modal.html.erb index 6d63cfe3..64c59e95 100644 --- a/app/views/shared/modals/_login_modal.html.erb +++ b/app/views/shared/modals/_login_modal.html.erb @@ -7,8 +7,8 @@

<%= t("login") %>

- <% unless configured_providers.length.zero? %> - <% configured_providers.each do |provider| %> + <% unless iconset_providers.length.zero? %> + <% iconset_providers.each do |provider| %> <%= link_to omniauth_login_url(provider), class: "btn btn-pill btn-#{provider} btn-block" do %>  <%= t("modal.login.with", provider: provider.capitalize) %> <% end %> diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 0fa094ea..4cfbbcd8 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true # List of supported Omniauth providers. -Rails.application.config.providers = [:google, :twitter] +Rails.application.config.providers = [:google, :twitter, :ldap] # Set which providers are configured. Rails.application.config.omniauth_google = ENV['GOOGLE_OAUTH2_ID'].present? && ENV['GOOGLE_OAUTH2_SECRET'].present? Rails.application.config.omniauth_twitter = ENV['TWITTER_ID'].present? && ENV['TWITTER_SECRET'].present? +Rails.application.config.omniauth_ldap = ENV['LDAP_SERVER'].present? && ENV['LDAP_UID'].present? && + ENV['LDAP_BASE'].present? && ENV['LDAP_BIND_DN'].present? && + ENV['LDAP_PASSWORD'].present? Rails.application.config.omniauth_bn_launcher = Rails.configuration.loadbalanced_configuration SETUP_PROC = lambda do |env| @@ -16,9 +19,9 @@ end Rails.application.config.middleware.use OmniAuth::Builder do if Rails.configuration.omniauth_bn_launcher provider :bn_launcher, client_id: ENV['CLIENT_ID'], - client_secret: ENV['CLIENT_SECRET'], - client_options: { site: ENV['BN_LAUNCHER_REDIRECT_URI'] }, - setup: SETUP_PROC + client_secret: ENV['CLIENT_SECRET'], + client_options: { site: ENV['BN_LAUNCHER_REDIRECT_URI'] }, + setup: SETUP_PROC end provider :twitter, ENV['TWITTER_ID'], ENV['TWITTER_SECRET'] @@ -28,4 +31,19 @@ Rails.application.config.middleware.use OmniAuth::Builder do access_type: 'online', name: 'google', hd: ENV['GOOGLE_OAUTH2_HD'].blank? ? nil : ENV['GOOGLE_OAUTH2_HD'] + + provider :ldap, + host: ENV['LDAP_SERVER'], + port: ENV['LDAP_PORT'] || '389', + method: ENV['LDAP_METHOD'].blank? ? :plain : ENV['LDAP_METHOD'].to_sym, + allow_username_or_email_login: true, + uid: ENV['LDAP_UID'], + base: ENV['LDAP_BASE'], + bind_dn: ENV['LDAP_BIND_DN'], + password: ENV['LDAP_PASSWORD'] end + +# Redirect back to login in development mode. +OmniAuth.config.on_failure = proc { |env| + OmniAuth::FailureEndpoint.new(env).redirect_to_failure +} diff --git a/config/locales/en.yml b/config/locales/en.yml index 0ac42048..9390dc8c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -42,6 +42,7 @@ en: settings: Settings signout: Sign out info_update_success: Information successfully updated. + invalid_credentials: Login failed due to invalid credentials. Are you sure you entered them correctly? invite_message: "To invite someone to the meeting, send them this link:" landing: about: A simple front end for your BigBlueButton Open Source Web Conferencing Server. @@ -49,8 +50,8 @@ en: video: Watch a tutorial on using Greenlight upgrade: Show me how to upgrade to 2.0! version: We've released a new version of Greenlight, but your database isn't compatible. + ldap_error: Unable to connect to the LDAP server. Please check your LDAP configuration in the env file and ensure your server is running. login: Login - login_failed: Login failed due to invalid credentials. Are you sure you typed them correctly? modal: create_room: auto_join: Automatically join me into the room. @@ -66,6 +67,7 @@ en: login: or: or with: Login with %{provider} + omniauth_error: An error occured while authenticating with omniauth. Please try again or contact an administrator! password: Password recording: email: Email Recording diff --git a/sample.env b/sample.env index 545f9f73..58f446d8 100644 --- a/sample.env +++ b/sample.env @@ -20,7 +20,7 @@ BIGBLUEBUTTON_SECRET= # # For in-depth steps on setting up a Google Login Provider, see: # -# http://docs.bigbluebutton.org/install/greenlight.html#google-oauth2 +# http://docs.bigbluebutton.org/install/greenlight-v2.html#google-oauth2 # # The GOOGLE_OAUTH2_HD variable is used to limit sign-in to a particular Google Apps hosted # domain. This can be a string such as, 'domain.com'. If left blank, GreenLight will allow @@ -33,11 +33,27 @@ GOOGLE_OAUTH2_HD= # # For in-depth steps on setting up a Twitter Login Provider, see: # -# http://docs.bigbluebutton.org/install/greenlight.html#twitter-oauth2 +# http://docs.bigbluebutton.org/install/greenlight-v2.html#twitter-oauth2 # TWITTER_ID= TWITTER_SECRET= +# LDAP Login Provider (optional) +# +# You can enable LDAP authentication by providing values for the variables below. +# Configuring LDAP authentication will take precedence over all other providers. +# For information about setting up LDAP, see: +# +# http://docs.bigbluebutton.org/install/green-light-v2.html#ldap-oauth +# +LDAP_SERVER= +LDAP_PORT= +LDAP_METHOD= +LDAP_UID= +LDAP_BASE= +LDAP_BIND_DN= +LDAP_PASSWORD= + # Set this to true if you want GreenLight to support user signup and login without # Omniauth. For more information, see: #