Skip to content

Commit

Permalink
Add the code for cert authentication, pulled from another repo
Browse files Browse the repository at this point in the history
  • Loading branch information
daronco committed Feb 20, 2017
1 parent c2e65aa commit 88da6d7
Show file tree
Hide file tree
Showing 51 changed files with 868 additions and 18 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ gem 'gravatar_image_tag'
# Captcha
gem 'recaptcha', require: 'recaptcha/rails'

# SOAP webservices
gem 'rubyntlm'
gem 'savon', '~> 2.0'

#
# TODO: Gems to review if we can remove/update
#
Expand Down
24 changes: 24 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ GEM
acts_as_tree (2.0.0)
activerecord (>= 3.0.0)
addressable (2.3.6)
akami (1.3.1)
gyoku (>= 0.4.0)
nokogiri
ansi (1.4.3)
arel (5.0.1.20140414130214)
bcrypt (3.1.10)
Expand Down Expand Up @@ -208,6 +211,8 @@ GEM
activerecord (>= 4.0.0)
geocoder (1.2.9)
gravatar_image_tag (1.2.0)
gyoku (1.3.1)
builder (>= 2.1.2)
haml (4.0.5)
tilt
handlebars_assets (0.17.1)
Expand All @@ -225,6 +230,9 @@ GEM
httparty (0.13.1)
json (~> 1.8)
multi_xml (>= 0.5.2)
httpi (2.4.2)
rack
socksify
i18n (0.7.0)
i18n-js (3.0.0.rc12)
i18n (~> 0.6, >= 0.6.6)
Expand Down Expand Up @@ -301,6 +309,7 @@ GEM
net-ssh-gateway (>= 1.2.0)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
nori (2.6.0)
ohai (8.0.1)
ffi (~> 1.9)
ffi-yajl (~> 1.1)
Expand Down Expand Up @@ -414,6 +423,7 @@ GEM
sexp_processor (~> 4.0)
ruby_parser (3.5.0)
sexp_processor (~> 4.1)
rubyntlm (0.6.1)
rubyzip (1.1.6)
rufus-scheduler (2.0.24)
tzinfo (>= 0.3.22)
Expand All @@ -424,6 +434,14 @@ GEM
sass (~> 3.2.2)
sprockets (~> 2.8, < 3.0)
sprockets-rails (~> 2.0)
savon (2.11.1)
akami (~> 1.2)
builder (>= 2.1.2)
gyoku (~> 1.2)
httpi (~> 2.3)
nokogiri (>= 1.4.0)
nori (~> 2.4)
wasabi (~> 3.4)
select2-rails (3.5.9)
thor (~> 0.14)
sexp_processor (4.4.4)
Expand All @@ -450,6 +468,7 @@ GEM
temple (~> 0.6.9)
tilt (>= 1.3.3, < 2.1)
slop (3.6.0)
socksify (1.7.0)
spring (1.3.4)
sprockets (2.12.4)
hike (~> 1.2)
Expand Down Expand Up @@ -496,6 +515,9 @@ GEM
vpim (13.11.11)
warden (1.2.6)
rack (>= 1.0)
wasabi (3.5.0)
httpi (~> 2.0)
nokogiri (>= 1.4.2)
webmock (1.21.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
Expand Down Expand Up @@ -601,8 +623,10 @@ DEPENDENCIES
rmagick (~> 2.13.2)
rspec-mocks
rspec-rails (~> 2.99.0)
rubyntlm
rubyzip (>= 1.0.0)
sass-rails (~> 4.0.4)
savon (~> 2.0)
select2-rails
shoulda-kept-assign-to
shoulda-matchers (~> 3.0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class mconf.CertificateAuthentication

redirect_on_success = ->
if $('.certificate-login-error').length == 0
window.location = '/home'

setTimeout redirect_on_success, 2000

# Binds all certificate authentication login modal events
@bind: ->

# Redirect after some time has passed
$('a#certificate-login').on 'modal-shown', ->
setTimeout redirect_on_success, 2000

$('a#certificate-login').on 'modal-hide', ->
redirect_on_success()

# Show an error message if server returns 40x or 50x
$('a#certificate-login').on 'modal-error', ->
$(this).addClass('certificate-login-error')
$('.modal.xhr-error').load('/certificate_error')
.hide()
.fadeIn('slow');
9 changes: 8 additions & 1 deletion app/assets/javascripts/app/application/modal.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,16 @@ class mconf.Modal

# if its a link, load the content and then show it
if isRemote
$modal.load options.target, "", ->
$modal.load options.target, "", (responseText, textStatus, xhr) ->
$modal.modal(localOptions)

# Remote returns an http error code show
if !(xhr.status >= 200 && xhr.status < 400)
$modal.addClass('xhr-error')
$modal.html("<div class='status'> <i class='fa fa-frown-o'></i> #{xhr.statusText} </div>")

$(options.element).trigger("modal-error")

# not a link, simply show the content
else
$modal.modal(localOptions)
Expand Down
3 changes: 3 additions & 0 deletions app/assets/javascripts/app/frontpage/show.js.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#= require "../registrations/_signup_form"
#= require "../application/certificate_authentication"

$ ->
if isOnPage 'frontpage', 'show'
mconf.SignupForm.setup()

mconf.CertificateAuthentication.bind()
5 changes: 5 additions & 0 deletions app/assets/javascripts/app/sessions/new.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#= require "../application/certificate_authentication"

$ ->
if isOnPage 'sessions', 'new|create'
mconf.CertificateAuthentication.bind()
1 change: 1 addition & 0 deletions app/assets/javascripts/sessions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//= require_tree ./app/sessions/
42 changes: 42 additions & 0 deletions app/assets/stylesheets/app/application/modal.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@
left: 60%;
}

.xhr-error {

.status {
display:flex;
justify-content:center;
align-items:center;
margin: 20px;
font-size: 200%;
i {
padding-right: 20px;
font-size: 300%;
}
}

}

@media (max-width: 979px) {
.modal-small {
left: 1%; // as done in bootstrap
Expand All @@ -25,3 +41,29 @@
border: 0;
background: none;
}

/* For the certificate pending modal in app/views/certificate_authentication/pending */
.certificate-pending {

margin: 0 auto;
float: none;
text-align: center;
max-width: $contents-width * 0.7;

.error-links {
margin: 30px 0;

ul {
margin: 0;
padding: 0;

display: inline;

li {
display: inline-block;
}

}
}

}
10 changes: 10 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ class ApplicationController < ActionController::Base
before_filter :set_time_zone
before_filter :store_location

# This will only happen if the user is logged in and his certificate has
# been revoked, it makes a call to the WS every request.
# TODO: Could be made better if the any_certificate? method had a cache
before_filter :check_attribute_certificate, if: -> { Rails.env.production? }
def check_attribute_certificate
if current_user.present? && !current_user.superuser? && !Mconf::AttributeCertificate.any_certificate?(current_user)
sign_out current_user
end
end

helper_method :current_site
helper_method :previous_path_or
helper_method :locale_i18n
Expand Down
49 changes: 49 additions & 0 deletions app/controllers/certificate_authentication_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
class CertificateAuthenticationController < ApplicationController

layout :determine_layout
def determine_layout
if request.xhr?
'modal'
else
'application'
end
end

def login
certificate = request.headers['SSL_CLIENT_CERT']

@cert = Mconf::SSLClientCert.new(certificate)
@user = @cert.user

if @user.present?

# If the user has permission, log him in
if Mconf::AttributeCertificate::any_certificate?(@user)
sign_in :user, @user
redirect_to my_home_path if !request.xhr?

# user present but has no permissions via his certificate
else
redirect_to certificate_pending_path(name: @user.name)
end

else
error = @cert.error || 'unknown'
flash[:error] = I18n.t("certificate_authentication.error.#{error}")
end
end

# Serves the error modal
def error
end

def pending
# don't show it unless user logged via certificate
# referers = [login_url, root_url, certificate_login_path]

if user_signed_in?
redirect_to root_path
end
end

end
1 change: 1 addition & 0 deletions app/controllers/sites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def allowed_params
:registration_enabled, :require_registration_approval, :local_auth_enabled, :events_enabled, :room_dial_number_pattern,
:shib_update_users, :require_space_approval, :forbid_user_space_creation, :max_upload_size, :use_gravatar,
:captcha_enabled, :recaptcha_public_key, :recaptcha_private_key, :unauth_access_to_conferences,
:certificate_login_enabled, :certificate_id_field, :certificate_user_id_field,
visible_locales: []
]
end
Expand Down
11 changes: 9 additions & 2 deletions app/models/abilities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
require 'abilities/member_ability'
require 'abilities/superuser_ability'

require './lib/mconf/attribute_certificate'

module Abilities

def self.ability_for(user)
if user and user.superuser?
ac_conf = AttributeCertificateConfiguration.first
use_certificates = ac_conf.try(:enabled?)

# Try superuser via certificate and then via normal method
if user && (use_certificates && Mconf::AttributeCertificate::role_for?(user, 'Global Admin') || user.superuser?)
#if user and user.superuser?
SuperUserAbility.new(user)
elsif user and !user.anonymous?
elsif user && !user.anonymous?
MemberAbility.new(user)
else
AnonymousAbility.new
Expand Down
23 changes: 23 additions & 0 deletions app/models/attribute_certificate_configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class AttributeCertificateConfiguration < ActiveRecord::Base
validates :repository_url, presence: true, if: :enabled?

before_save :adjust_repository_url, if: :repository_url

def full_url
return '' if repository_url.blank?

port = repository_port || '443'
port_str = ":#{port}/" unless ['80','443'].include?(port)

"http#{port == '443' ? 's' : ''}://#{repository_url}#{port_str}?wsdl"
end


private

def adjust_repository_url
repository_url.gsub!(/\?wsdl$/, '') # remove ?wsdl from the url
repository_url.gsub!(/^https?:\/\//, '') # remove protocol from the start
end

end
13 changes: 13 additions & 0 deletions app/models/attribute_role.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class AttributeRole < ActiveRecord::Base
belongs_to :role

def self.find_by_role_name name
r = Role.where(name: name).first

where(role: r).first
end

def role_name
role.try(:name)
end
end
4 changes: 4 additions & 0 deletions app/models/site.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class Site < ActiveRecord::Base

before_validation :validate_and_adjust_max_upload_size

def self.roles
{ admin: Role.where(name: 'Global Admin').first }
end

# Returns the current (default) site
def self.current
first || create
Expand Down
15 changes: 15 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ def self.find_first_by_auth_conditions(warden_conditions)
extend FriendlyId
friendly_id :username

validates :public_key, uniqueness: true, allow_nil: true
validates :unique_name, uniqueness: true, allow_nil: true

validates :email, uniqueness: true, presence: true, email: true

has_and_belongs_to_many :spaces, -> { where(permissions: {subject_type: 'Space'}).uniq },
Expand Down Expand Up @@ -335,6 +338,18 @@ def last_sign_in_method
[shib_token, ldap_token, self].reject(&:blank?).sort_by{ |method| method.last_sign_in_date || Time.at(0) }.last.sign_in_method_name
end

def superuser
Permission.where(subject: Site.current, user: self, role: Site.roles[:admin]).first.present?
end

def superuser?
superuser
end

def set_superuser!
Permission.find_or_create_by(subject: Site.current, user: self, role: Site.roles[:admin])
end

protected

def before_disable_and_destroy
Expand Down
3 changes: 3 additions & 0 deletions app/views/certificate_authentication/_error.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.certificate-login-error
= flash[:error] || t('.generic')
= icon_error()
3 changes: 3 additions & 0 deletions app/views/certificate_authentication/error.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.modal-body
- content_for :modal_title, t('.title')
= render 'error'
Loading

0 comments on commit 88da6d7

Please sign in to comment.