GRN2-30: Add custom ldap sign in page (#619)

* Add custom ldap signin page

* Remove old omniauth-ldap gem

* Use new bn gems
This commit is contained in:
shawn-higgins1 2019-07-10 11:26:43 -04:00 committed by Jesus Federico
parent 09afd9154f
commit 523d9a38f2
14 changed files with 180 additions and 82 deletions

View File

@ -45,8 +45,9 @@ gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-google-oauth2'
gem 'omniauth-bn-office365', git: 'https://github.com/blindsidenetworks/omniauth-bn-office365.git', tag: '0.1.0'
gem 'omniauth-ldap'
gem 'omniauth-bn-launcher', git: 'https://github.com/blindsidenetworks/omniauth-bn-launcher.git', tag: '0.1.0'
gem 'omniauth-bn-launcher', git: 'https://github.com/blindsidenetworks/omniauth-bn-launcher.git', tag: '0.1.1'
gem 'bn-ldap-authentication', git: 'https://github.com/blindsidenetworks/bn-ldap-authentication.git'
gem 'net-ldap'
# BigBlueButton API wrapper.
gem 'bigbluebutton-api-ruby'

View File

@ -1,9 +1,16 @@
GIT
remote: https://github.com/blindsidenetworks/bn-ldap-authentication.git
revision: 538132e0df70dbe470120f7bc7a93968c522031f
specs:
bn-ldap-authentication (1.0.0)
net-ldap
GIT
remote: https://github.com/blindsidenetworks/omniauth-bn-launcher.git
revision: 0d0597bec9aed63b9c9d44e99e16353c5d587d48
tag: 0.1.0
revision: 025785046c3d532ed2252ef4762469c8d08d4839
tag: 0.1.1
specs:
omniauth-bn-launcher (0.1.0)
omniauth-bn-launcher (0.1.1)
omniauth (~> 1.3, >= 1.3.2)
omniauth-oauth2 (= 1.5.0)
@ -165,11 +172,6 @@ GEM
jwt (>= 2.0)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.5)
omniauth-ldap (1.0.5)
net-ldap (~> 0.12)
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.2)
rubyntlm (~> 0.3.4)
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
@ -187,7 +189,6 @@ GEM
popper_js (1.14.5)
public_suffix (3.0.3)
puma (3.12.1)
pyu-ruby-sasl (0.0.3.3)
rack (2.0.7)
rack-test (0.6.3)
rack (>= 1.0)
@ -256,7 +257,6 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
ruby-progressbar (1.10.0)
rubyntlm (0.3.4)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
@ -336,6 +336,7 @@ DEPENDENCIES
action-cable-testing
bcrypt (~> 3.1.7)
bigbluebutton-api-ruby
bn-ldap-authentication!
bootstrap (~> 4.3.1)
byebug
cancancan (~> 2.0)
@ -351,11 +352,11 @@ DEPENDENCIES
jquery-rails (~> 4.3.3)
listen (~> 3.0.5)
mini_racer
net-ldap
omniauth
omniauth-bn-launcher!
omniauth-bn-office365!
omniauth-google-oauth2
omniauth-ldap
omniauth-twitter
pagy
pg (~> 0.18)

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -145,6 +145,17 @@
}
}
.customBtn-ldap {
@extend .customBtn;
background: #d61515;
.customBtn-image {
background: #ffffff image-url("ldap-logo.png") no-repeat left top;
background-size: 18px 18px;
padding:10px 10px 10px 10px;
}
}
.signin-button {
font-size: 16px;
}

View File

@ -19,6 +19,7 @@
class SessionsController < ApplicationController
include Registrar
include Emailer
include LdapAuthenticator
skip_before_action :verify_authenticity_token, only: [:omniauth, :fail]
@ -47,8 +48,65 @@ class SessionsController < ApplicationController
# GET/POST /auth/:provider/callback
def omniauth
@auth = request.env['omniauth.auth']
process_signin
end
# POST /auth/failure
def omniauth_fail
redirect_to root_path, alert: I18n.t(params[:message], default: I18n.t("omniauth_error"))
end
# GET /auth/ldap
def ldap
ldap_config = {}
ldap_config[:host] = ENV['LDAP_SERVER']
ldap_config[:port] = ENV['LDAP_PORT'].to_i != 0 ? ENV['LDAP_PORT'].to_i : 389
ldap_config[:bind_dn] = ENV['LDAP_BIND_DN']
ldap_config[:password] = ENV['LDAP_PASSWORD']
ldap_config[:encryption] = if ENV['LDAP_METHOD'] == 'ssl'
'simple_tls'
elsif ENV['LDAP_METHOD'] == 'tls'
'start_tls'
end
ldap_config[:base] = ENV['LDAP_BASE']
ldap_config[:uid] = ENV['LDAP_UID']
result = send_ldap_request(params[:session], ldap_config)
if result
result = result.first
else
return redirect_to(ldap_signin_path, alert: I18n.t("invalid_credentials"))
end
@auth = parse_auth(result)
process_signin
end
private
def session_params
params.require(:session).permit(:email, :password)
end
def check_user_exists
provider = @auth['provider'] == "bn_launcher" ? @auth['info']['customer'] : @auth['provider']
User.exists?(social_uid: @auth['uid'], provider: provider)
end
# Check if the user already exists, if not then check for invitation
def passes_invite_reqs
return true if @user_exists
invitation = check_user_invited("", session[:invite_token], @user_domain)
invitation[:present]
end
def process_signin
begin
@auth = request.env['omniauth.auth']
@user_exists = check_user_exists
if !@user_exists && @auth['provider'] == "twitter"
@ -89,28 +147,4 @@ class SessionsController < ApplicationController
omniauth_fail
end
end
# POST /auth/failure
def omniauth_fail
redirect_to root_path, alert: I18n.t(params[:message], default: I18n.t("omniauth_error"))
end
private
def session_params
params.require(:session).permit(:email, :password)
end
def check_user_exists
provider = @auth['provider'] == "bn_launcher" ? @auth['info']['customer'] : @auth['provider']
User.exists?(social_uid: @auth['uid'], provider: provider)
end
# Check if the user already exists, if not then check for invitation
def passes_invite_reqs
return true if @user_exists
invitation = check_user_invited("", session[:invite_token], @user_domain)
invitation[:present]
end
end

View File

@ -68,6 +68,10 @@ class UsersController < ApplicationController
end
end
# GET /ldap_signin
def ldap_signin
end
# GET /signup
def new
return redirect_to root_path unless Rails.configuration.allow_user_signup

View File

@ -33,7 +33,7 @@ module ApplicationHelper
# Determines which providers can show a login button in the login modal.
def iconset_providers
providers = configured_providers & [:google, :twitter, :microsoft_office365]
providers = configured_providers & [:google, :twitter, :microsoft_office365, :ldap]
providers.delete(:twitter) if session[:old_twitter_user_id]
@ -42,7 +42,11 @@ module ApplicationHelper
# Generates the login URL for a specific provider.
def omniauth_login_url(provider)
"#{Rails.configuration.relative_url_root}/auth/#{provider}"
if provider == :ldap
ldap_signin_path
else
"#{Rails.configuration.relative_url_root}/auth/#{provider}"
end
end
# Determine if Greenlight is configured to allow user signups.

View File

@ -72,9 +72,7 @@
</div>
<% else %>
<% allow_greenlight_accounts = allow_greenlight_accounts? %>
<% if Rails.configuration.omniauth_ldap %>
<%= link_to t("login"), omniauth_login_url(:ldap), :class => "btn btn-outline-primary mx-2 sign-in-button" %>
<% elsif allow_greenlight_accounts %>
<% if allow_greenlight_accounts %>
<%= link_to t("login"), signin_path, :class => "btn btn-outline-primary mx-2 sign-in-button" %>
<% elsif Rails.configuration.loadbalanced_configuration %>
<%= link_to t("login"), omniauth_login_url(:bn_launcher), :class => "btn btn-outline-primary mx-2 sign-in-button" %>

View File

@ -0,0 +1,34 @@
<div class="container">
<div class="row pt-7">
<div class="col col-lg-6 offset-lg-3">
<div class="card">
<div class="card-header background">
<h4 class="mt-2"><%= t("login_title") %></h4>
</div>
<div class="card-body background">
<%= form_for(:session, url: ldap_callback_path) do |f| %>
<div class="form-group">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fas fa-user"></i>
</span>
<%= f.text_field :username, class: "form-control", placeholder: t("administrator.users.table.username"), value: "" %>
</div>
</div>
<div class="form-group">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fas fa-key"></i>
</span>
<%= f.password_field :password, class: "form-control", placeholder: t("password"), value: "" %>
</div>
</div>
<div>
<%= f.submit t("login"), class: "btn btn-primary btn-block signin-button" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>

View File

@ -15,9 +15,6 @@ Rails.application.config.omniauth_google = ENV['GOOGLE_OAUTH2_ID'].present? && E
Rails.application.config.omniauth_office365 = ENV['OFFICE365_KEY'].present? &&
ENV['OFFICE365_SECRET'].present?
# If LDAP is enabled, override and disable allow_user_signup.
Rails.application.config.allow_user_signup = false if Rails.application.config.omniauth_ldap
SETUP_PROC = lambda do |env|
SessionsController.helpers.omniauth_options env
end
@ -29,19 +26,9 @@ Rails.application.config.middleware.use OmniAuth::Builder do
client_secret: ENV['CLIENT_SECRET'],
client_options: { site: ENV['BN_LAUNCHER_URI'] || ENV['BN_LAUNCHER_REDIRECT_URI'] },
setup: SETUP_PROC
elsif Rails.configuration.omniauth_ldap
Rails.application.config.providers << :ldap
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']
else
Rails.application.config.providers << :ldap if Rails.configuration.omniauth_ldap
if Rails.configuration.omniauth_twitter
Rails.application.config.providers << :twitter
@ -69,27 +56,3 @@ end
OmniAuth.config.on_failure = proc { |env|
OmniAuth::FailureEndpoint.new(env).redirect_to_failure
}
# Work around beacuse callback_url option causes
# omniauth.auth to be nil in the authhash when
# authenticating with LDAP.
module OmniAuthLDAPExt
def request_phase
rel_root = ENV['RELATIVE_URL_ROOT'].present? ? ENV['RELATIVE_URL_ROOT'] : '/b'
@callback_path = nil
path = options[:callback_path]
options[:callback_path] = "#{rel_root if Rails.env == 'production'}/auth/ldap/callback"
form = super
options[:callback_path] = path
form
end
end
module OmniAuth
module Strategies
class LDAP
prepend OmniAuthLDAPExt
end
end
end

View File

@ -302,6 +302,7 @@ en:
google: Google
office365: Office 365
twitter: Twitter
ldap: LDAP
recaptcha:
errors:
recaptcha_unreachable: Oops, we failed to validate your reCAPTCHA response. Please try again.

View File

@ -29,6 +29,7 @@ Rails.application.routes.draw do
get '/signin', to: 'users#signin', as: :signin
get '/signup', to: 'users#new', as: :signup
post '/signup', to: 'users#create', as: :create_user
get '/ldap_signin', to: 'users#ldap_signin', as: :ldap_signin
# Redirect to terms page
match '/terms', to: 'users#terms', via: [:get, :post]
@ -88,6 +89,7 @@ Rails.application.routes.draw do
# Handles Omniauth authentication.
match '/auth/:provider/callback', to: 'sessions#omniauth', via: [:get, :post], as: :omniauth_session
get '/auth/failure', to: 'sessions#omniauth_fail'
post '/auth/ldap', to: 'sessions#ldap', as: :ldap_callback
# Room resources.
resources :rooms, only: [:create, :show, :destroy], param: :room_uid, path: '/'

View File

@ -336,4 +336,41 @@ describe SessionsController, type: :controller do
expect(response).to redirect_to(root_path)
end
end
describe "POST #ldap" do
it "should create and login a user with a ldap login" do
entry = Net::LDAP::Entry.new("cn=Test User,ou=people,dc=planetexpress,dc=com")
entry[:cn] = "Test User"
entry[:givenName] = "Test"
entry[:sn] = "User"
entry[:mail] = "test@example.com"
allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return([entry])
post :ldap, params: {
session: {
user: "test",
password: 'password',
},
}
u = User.last
expect(u.provider).to eql("ldap")
expect(u.email).to eql("test@example.com")
expect(@request.session[:user_id]).to eql(u.id)
end
it "should redirect to signin on invalid credentials" do
allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return(false)
post :ldap, params: {
session: {
user: "test",
password: 'passwor',
},
}
expect(response).to redirect_to(ldap_signin_path)
expect(flash[:alert]).to eq(I18n.t("invalid_credentials"))
end
end
end

View File

@ -387,4 +387,12 @@ describe UsersController, type: :controller do
expect(response).to redirect_to(root_path)
end
end
context 'GET #ldap_signin' do
it "should render the ldap signin page" do
get :ldap_signin
expect(response).to render_template(:ldap_signin)
end
end
end