puavo_authentication 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,9 +6,9 @@ class SessionsController < ApplicationController
6
6
  end
7
7
 
8
8
  def create
9
- if user = User.authenticate( params[:user][:uid], params[:user][:password] ) # REST/OAuth?
9
+ if user_dn = User.authenticate( params[:user][:uid], params[:user][:password] ) # REST/OAuth?
10
10
  flash[:notice] = t('flash.session.login_successful')
11
- session[:dn] = user.dn
11
+ session[:dn] = user_dn
12
12
  session[:password_plaintext] = params[:user][:password]
13
13
 
14
14
  #redirect_back_or_default schools_url
@@ -4,35 +4,89 @@ module Puavo
4
4
  base.send :extend, ClassMethods
5
5
  end
6
6
 
7
+
7
8
  module ClassMethods
9
+
10
+ def dn_cache_key(login_uid)
11
+ "user_dn:#{ login_uid }"
12
+ end
13
+
14
+ def delete_caches(login_uid)
15
+ Rails.cache.delete dn_cache_key login_uid
16
+ end
17
+
18
+ # Authenticate user with login username and password.
19
+ # Returns user dn string on successful login or false on invalid login
8
20
  def authenticate(login, password)
9
- logger.debug "Find user by uid from ldap"
10
- logger.debug "uid: #{login}"
11
21
 
12
- begin
22
+ # To authenticate an user we need to make a LDAP bind with user's dn
23
+ # and password. Lets look it up from cache:
24
+ user_dn = Rails.cache.fetch dn_cache_key(login) do
25
+ # On cache miss we need to use the Puavo credentials from config/ldap.yml
26
+ # to fetch the user object which contains the user dn.
27
+
28
+ # This find call actually initializes the LDAP connection under the
29
+ # hood with Puavo credentials.
13
30
  user = self.find(:first, :attribute => "uid", :value => login)
14
31
 
15
- if user.bind(password)
16
- host = LdapBase.configuration[:host]
17
- base = LdapBase.base.to_s
18
- user.remove_connection
19
- LdapBase.ldap_setup_connection(host, base, user.dn, password)
20
-
21
- # Allow authentication always if logged in user is ExteralService object
22
- if user.class == ExternalService
23
- return user
24
- end
25
-
26
- # Allow authetication only if user is School Admin in the some School or organisation owner.
27
- if School.find( :first, :attribute => "puavoSchoolAdmin", :value => user.dn ) ||
28
- LdapOrganisation.first.owner.include?(user.dn)
29
- return user
30
- end
32
+ # Remove connection made with Puavo credentials
33
+ self.remove_connection
34
+
35
+ if user.nil?
36
+ return nil
31
37
  end
32
- rescue Exception => e
33
- logger.info "Login failed: login: #{login}, Exception: #{e}"
38
+
39
+ user.dn
40
+ end
41
+
42
+ if user_dn.nil?
43
+ logger.info "Login failed for #{ login }: Unknown username"
34
44
  return false
35
45
  end
46
+
47
+ # Setup new ActiveLdap connections to use user's credentials
48
+ LdapBase.ldap_setup_connection(
49
+ LdapBase.configuration[:host],
50
+ LdapBase.base.to_s,
51
+ user_dn,
52
+ password)
53
+
54
+ # Do not never ever allow anonymous connections in Puavo. Should be
55
+ # false in config/ldap.yml, but we just make sure here.
56
+ self.connection.instance_variable_set :@allow_anonymous, false
57
+
58
+ # This is the first time when LDAP connection is used with the user's
59
+ # credentials. So this search call will initialize the connection and
60
+ # will raise ActiveLdap::AuthenticationError if user supplied a
61
+ # bad password.
62
+ begin
63
+ admin_permissions = School.search(
64
+ :filter => "(puavoSchoolAdmin=#{user_dn})",
65
+ :scope => :one, :attributes => ["puavoId"],
66
+ :limit => 1 )
67
+ rescue ActiveLdap::AuthenticationError
68
+ logger.info "Login failed for #{ login } (#{ user_dn }): Bad password"
69
+ return false
70
+ end
71
+
72
+ # Allow authentication if user is a school admin in the some school.
73
+ if not admin_permissions.empty?
74
+ return user_dn
75
+ end
76
+
77
+ # Allow authentication if user is an organisation owner
78
+ organisation = LdapOrganisation.first
79
+ if organisation && organisation.owner.include?(user_dn)
80
+ return user_dn
81
+ end
82
+
83
+ # Allow authentication always if logged in user an external service
84
+ if user_dn.rdns[1]["ou"] == "System Accounts"
85
+ return user_dn
86
+ end
87
+
88
+ logger.info "Login failed for #{ login } (#{ user_dn }): Not school admin or organisation owner"
89
+ return false
36
90
  end
37
91
  end
38
92
  end
@@ -26,16 +26,15 @@ module PuavoAuthentication
26
26
  logger.debug "Using HTTP basic authentication"
27
27
  password = ""
28
28
 
29
- user = authenticate_with_http_basic do |login, password|
29
+ user_dn = authenticate_with_http_basic do |login, password|
30
30
  if login.match(/^service\//)
31
31
  ExternalService.authenticate(login.match(/^service\/(.*)/)[1], password)
32
32
  else
33
33
  User.authenticate(login, password)
34
34
  end
35
35
  end
36
- logger.debug "Basic Auth User: " + user.inspect
37
- if user
38
- session[:dn] = user.dn
36
+ if user_dn
37
+ session[:dn] = user_dn
39
38
  session[:password_plaintext] = password
40
39
  logger.debug "Logged in with http basic authentication"
41
40
  else
@@ -71,15 +70,16 @@ module PuavoAuthentication
71
70
  if session[:dn]
72
71
  dn = session[:dn]
73
72
  password = session[:password_plaintext]
73
+ logger.debug "Using user's credentials for LDAP connection"
74
74
  else
75
+ logger.debug "Using Puavo credentials for LDAP connection"
75
76
  dn = default_ldap_configuration["bind_dn"]
76
77
  password = default_ldap_configuration["password"]
77
78
  end
78
79
  logger.debug "Set host, bind_dn, base and password by user:"
79
80
  logger.debug "host: #{host}"
80
81
  logger.debug "base: #{base}"
81
- logger.debug "dn: #{session[:dn]}"
82
- #logger.debug "password: #{session[:password_plaintext]}"
82
+ logger.debug "dn: #{dn}"
83
83
  LdapBase.ldap_setup_connection(host, base, dn, password)
84
84
  end
85
85
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puavo_authentication
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jouni Korhonen