jungle_path 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +22 -0
- data/README.md +5 -0
- data/jungle_path.gemspec +43 -0
- data/lib/jungle_path/api/helpers/auth.rb +45 -0
- data/lib/jungle_path/api/helpers/auth_local_user.rb +284 -0
- data/lib/jungle_path/api/helpers/auth_old.rb +232 -0
- data/lib/jungle_path/api/helpers/data_cache.rb +20 -0
- data/lib/jungle_path/api/helpers/defaults.rb +83 -0
- data/lib/jungle_path/api/helpers/logging.rb +36 -0
- data/lib/jungle_path/api/helpers/query_filters.rb +15 -0
- data/lib/jungle_path/api/helpers/rescues.rb +15 -0
- data/lib/jungle_path/api/helpers/result.rb +16 -0
- data/lib/jungle_path/api/helpers/standard_apis.rb +280 -0
- data/lib/jungle_path/api/helpers.rb +16 -0
- data/lib/jungle_path/api/template.erb +35 -0
- data/lib/jungle_path/api.rb +5 -0
- data/lib/jungle_path/app/a.gitignore +1 -0
- data/lib/jungle_path/app/api/server_base.rb +95 -0
- data/lib/jungle_path/app/api/server_custom.rb +121 -0
- data/lib/jungle_path/app/api/server_gen.rb +11 -0
- data/lib/jungle_path/app/auth/authorization.rb +96 -0
- data/lib/jungle_path/app/config/a.gitignore +1 -0
- data/lib/jungle_path/app/config/config.rb +240 -0
- data/lib/jungle_path/app/config/override.rb +3 -0
- data/lib/jungle_path/app/config.ru +28 -0
- data/lib/jungle_path/app/logs/log_files_go_here +0 -0
- data/lib/jungle_path/app/run.sh +4 -0
- data/lib/jungle_path/app/schemas/schema.rb +21 -0
- data/lib/jungle_path/app/schemas/schema_all_in_one.rb +181 -0
- data/lib/jungle_path/app.rb +8 -0
- data/lib/jungle_path/authentication/auth_provider/default.rb +83 -0
- data/lib/jungle_path/authentication/auth_provider.rb +7 -0
- data/lib/jungle_path/authentication/data_provider/default.rb +144 -0
- data/lib/jungle_path/authentication/data_provider.rb +7 -0
- data/lib/jungle_path/authentication/helpers.rb +19 -0
- data/lib/jungle_path/authentication/identity.rb +30 -0
- data/lib/jungle_path/authentication/password_hash.rb +124 -0
- data/lib/jungle_path/authentication.rb +9 -0
- data/lib/jungle_path/authorization/filter.rb +106 -0
- data/lib/jungle_path/authorization/paths.rb +71 -0
- data/lib/jungle_path/authorization.rb +5 -0
- data/lib/jungle_path/cache.rb +36 -0
- data/lib/jungle_path/config.rb +65 -0
- data/lib/jungle_path/controller/authentication.rb +129 -0
- data/lib/jungle_path/controller/base.rb +193 -0
- data/lib/jungle_path/controller/helpers.rb +47 -0
- data/lib/jungle_path/controller/template.erb +14 -0
- data/lib/jungle_path/controller.rb +7 -0
- data/lib/jungle_path/db_access/import/db_dir.rb +74 -0
- data/lib/jungle_path/db_access/import/delete.rb +30 -0
- data/lib/jungle_path/db_access/import/insert.rb +168 -0
- data/lib/jungle_path/db_access/import/schema.rb +34 -0
- data/lib/jungle_path/db_access/import/select.rb +68 -0
- data/lib/jungle_path/db_access/import.rb +15 -0
- data/lib/jungle_path/db_access/io/chunked_file_reader.rb +62 -0
- data/lib/jungle_path/db_access/io/config.rb +19 -0
- data/lib/jungle_path/db_access/io/copy.rb +73 -0
- data/lib/jungle_path/db_access/io/db.rb +82 -0
- data/lib/jungle_path/db_access/io/delete.rb +23 -0
- data/lib/jungle_path/db_access/io/init_db.rb +39 -0
- data/lib/jungle_path/db_access/io/insert.rb +24 -0
- data/lib/jungle_path/db_access/io/schema.rb +21 -0
- data/lib/jungle_path/db_access/io/select.rb +44 -0
- data/lib/jungle_path/db_access/io/update.rb +36 -0
- data/lib/jungle_path/db_access/io.rb +104 -0
- data/lib/jungle_path/db_model/column.rb +186 -0
- data/lib/jungle_path/db_model/params.rb +60 -0
- data/lib/jungle_path/db_model/schema.rb +100 -0
- data/lib/jungle_path/db_model/string.rb +9 -0
- data/lib/jungle_path/db_model/table.rb +307 -0
- data/lib/jungle_path/db_model.rb +34 -0
- data/lib/jungle_path/exceptions.rb +10 -0
- data/lib/jungle_path/gen/api.rb +52 -0
- data/lib/jungle_path/gen/controller.rb +0 -0
- data/lib/jungle_path/gen/db.rb +0 -0
- data/lib/jungle_path/gen/schema.rb +47 -0
- data/lib/jungle_path/gen/schema_tree/filter.rb +33 -0
- data/lib/jungle_path/gen/schema_tree/match_columns.rb +54 -0
- data/lib/jungle_path/gen/schema_tree/match_table_data.rb +22 -0
- data/lib/jungle_path/gen/schema_tree/match_tables.rb +70 -0
- data/lib/jungle_path/gen/schema_tree/node.rb +39 -0
- data/lib/jungle_path/gen/schema_tree.rb +105 -0
- data/lib/jungle_path/gen.rb +9 -0
- data/lib/jungle_path/json/base.rb +29 -0
- data/lib/jungle_path/json/time.rb +8 -0
- data/lib/jungle_path/json.rb +6 -0
- data/lib/jungle_path/logging.rb +23 -0
- data/lib/jungle_path/query/alias_info.rb +16 -0
- data/lib/jungle_path/query/engine.rb +878 -0
- data/lib/jungle_path/query/entity.rb +141 -0
- data/lib/jungle_path/query/field.rb +28 -0
- data/lib/jungle_path/query/field_primary_key.rb +27 -0
- data/lib/jungle_path/query/filter.rb +34 -0
- data/lib/jungle_path/query/float_value.rb +16 -0
- data/lib/jungle_path/query/from.rb +33 -0
- data/lib/jungle_path/query/int_value.rb +16 -0
- data/lib/jungle_path/query/limit.rb +19 -0
- data/lib/jungle_path/query/nested_hash_sorter.rb +94 -0
- data/lib/jungle_path/query/operator.rb +17 -0
- data/lib/jungle_path/query/query.rb +23 -0
- data/lib/jungle_path/query/sort_field.rb +34 -0
- data/lib/jungle_path/query/sql_string.rb +145 -0
- data/lib/jungle_path/query/string_value.rb +16 -0
- data/lib/jungle_path/query.rb +19 -0
- data/lib/jungle_path/rack/basic_credentials.rb +70 -0
- data/lib/jungle_path/rack/json_body_parser.rb +41 -0
- data/lib/jungle_path/rack.rb +6 -0
- data/lib/jungle_path/schema/auth.rb +83 -0
- data/lib/jungle_path/schema/base.rb +6 -0
- data/lib/jungle_path/schema/db.rb +10 -0
- data/lib/jungle_path/schema/version.rb +19 -0
- data/lib/jungle_path/schema.rb +8 -0
- data/lib/jungle_path/sql/auth_local_user.rb +5 -0
- data/lib/jungle_path/sql/general.rb +10 -0
- data/lib/jungle_path/sql/helpers.rb +11 -0
- data/lib/jungle_path/sql/key.rb +107 -0
- data/lib/jungle_path/sql/query_filter.rb +5 -0
- data/lib/jungle_path/sql/role.rb +5 -0
- data/lib/jungle_path/sql/user.rb +35 -0
- data/lib/jungle_path/sql/user_role.rb +5 -0
- data/lib/jungle_path/sql.rb +12 -0
- data/lib/jungle_path.rb +13 -0
- data/test.rb +33 -0
- data/test2.rb +15 -0
- metadata +200 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
# schema.rb
|
2
|
+
require 'jungle_path/db_model'
|
3
|
+
require 'jungle_path/schema'
|
4
|
+
|
5
|
+
module Schema
|
6
|
+
# schema meta data:
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
# Specify database version number.
|
10
|
+
# This version number will be used to apply database
|
11
|
+
# migrations.
|
12
|
+
# If the configatron.db.name does not exist, then
|
13
|
+
# this schema is applied directly and the appropriate
|
14
|
+
# version number is recorded in the database.
|
15
|
+
# Version of nil will run all available migrations
|
16
|
+
#1
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.migrations_path
|
21
|
+
::File.expand_path('../ztools/db/migrations',::File.dirname(__FILE__))
|
22
|
+
end
|
23
|
+
|
24
|
+
# base table:
|
25
|
+
|
26
|
+
class Base < DBModel::Table
|
27
|
+
end
|
28
|
+
|
29
|
+
# Used for database versioning with Sequel migrations:
|
30
|
+
class SchemaInfo < Schema::Base
|
31
|
+
self.description = "Used by sequel migration."
|
32
|
+
define(
|
33
|
+
[:version, :integer, :primary_key]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# application tables examples:
|
38
|
+
|
39
|
+
class Answer < Schema::Base
|
40
|
+
self.description = ""
|
41
|
+
define(
|
42
|
+
[:id, :primary_key],
|
43
|
+
[:question_id, :foreign_key, :question],
|
44
|
+
[:description, :string],
|
45
|
+
[:is_correct, :boolean],
|
46
|
+
[:audit_user]
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
class Practice < Schema::Base
|
51
|
+
self.description = ""
|
52
|
+
define(
|
53
|
+
[:id, :primary_key],
|
54
|
+
[:user_id, :foreign_key, :user],
|
55
|
+
[:notes, :string],
|
56
|
+
[:random_question_order, :boolean],
|
57
|
+
[:random_answer_order, :boolean],
|
58
|
+
[:audit_user]
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
class PracticeQuiz < Schema::Base
|
63
|
+
self.description = ""
|
64
|
+
define(
|
65
|
+
[:practice_id, :foreign_key, :practice, :primary_key],
|
66
|
+
[:quiz_id, :foreign_key, :quiz, :primary_key],
|
67
|
+
[:audit_user]
|
68
|
+
)
|
69
|
+
def self.plural_table_name
|
70
|
+
"practice_quizzes"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class PracticeQuestion < Schema::Base
|
75
|
+
self.description = ""
|
76
|
+
define(
|
77
|
+
[:practice_id, :foreign_key, :practice, :primary_key],
|
78
|
+
[:question_id, :foreign_key, :question, :primary_key],
|
79
|
+
[:note, :string],
|
80
|
+
[:audit_user]
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
class PracticeAnswer < Schema::Base
|
85
|
+
self.description = ""
|
86
|
+
define(
|
87
|
+
[:practice_id, :foreign_key, :practice, :primary_key],
|
88
|
+
[:answer_id, :foreign_key, :answer, :primary_key],
|
89
|
+
[:label, :string],
|
90
|
+
[:selected, :boolean],
|
91
|
+
[:audit_user]
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
class Question < Schema::Base
|
96
|
+
self.description = ""
|
97
|
+
define(
|
98
|
+
[:id, :primary_key],
|
99
|
+
[:quiz_id, :foreign_key, :quiz],
|
100
|
+
[:name, :string],
|
101
|
+
[:description, :string],
|
102
|
+
[:audit_user]
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
class Quiz < Schema::Base
|
107
|
+
self.description = ""
|
108
|
+
define(
|
109
|
+
[:id, :primary_key],
|
110
|
+
[:name, :string],
|
111
|
+
[:description, :string],
|
112
|
+
[:private, :boolean, :default, true],
|
113
|
+
[:audit_user]
|
114
|
+
)
|
115
|
+
def self.plural_table_name
|
116
|
+
"quizzes"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Log < Schema::Base
|
121
|
+
define(
|
122
|
+
[:id, :primary_key],
|
123
|
+
[:set_id, :integer],
|
124
|
+
[:name, :string],
|
125
|
+
[:type, :string],
|
126
|
+
[:item, :string, :secure],
|
127
|
+
[:timestamp, :timestamp]
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
class Role < Schema::Base
|
133
|
+
self.description = "User authorization: Roles for Users to assume in system."
|
134
|
+
define(
|
135
|
+
[:id, :primary_key],
|
136
|
+
[:name, :string, :unique_index, [:name], :not_null],
|
137
|
+
[:description, :string],
|
138
|
+
[:audit_user]
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
class User < Schema::Base
|
145
|
+
self.description = "User of system."
|
146
|
+
define(
|
147
|
+
[:id, :primary_key],
|
148
|
+
[:name, :string, :desc, "Your human name! :)"],
|
149
|
+
[:first_name, :string, :index],
|
150
|
+
[:last_name, :string, :index],
|
151
|
+
[:user_name, :string, :unique, :not_null, :alternate_key, :desc, "may use an email address as a user_name"],
|
152
|
+
[:email, :string, :index],
|
153
|
+
[:phone, :string, :desc, "mobile phone number", :index],
|
154
|
+
[:sms_verification_code, :string, :secure, :desc, "phone verification/sign-in code."],
|
155
|
+
[:hash, :string, :not_null, :secure, :calculated, :desc, "See password_hash.rb for details."],
|
156
|
+
[:key, :string, :unique, :secure, :calculated, :desc, "Used as alternative to user_name/password."],
|
157
|
+
[:activation_key, :string, :secure],
|
158
|
+
[:active, :boolean],
|
159
|
+
[:is_valid, :boolean, :calculated],
|
160
|
+
[:password_reset_code, :string, :secure],
|
161
|
+
[:audit_user]
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
class User
|
166
|
+
@auth
|
167
|
+
@query_filters
|
168
|
+
@password
|
169
|
+
attr_accessor :auth, :query_filters, :password
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
class UserRole < Schema::Base
|
174
|
+
self.description = "Assign authorization roles to users of system."
|
175
|
+
define(
|
176
|
+
[:user_id, :foreign_key, :user, :primary_key],
|
177
|
+
[:role_id, :foreign_key, :role, :primary_key],
|
178
|
+
[:audit_user]
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module JunglePath
|
2
|
+
module Authentication
|
3
|
+
module AuthProvider
|
4
|
+
class Default
|
5
|
+
def authenticate request, data_provider=nil, no_cache=false
|
6
|
+
puts "Auth.authenticate"
|
7
|
+
data_provider = JunglePath::Authentication::DataProvider::Default.new unless data_provider
|
8
|
+
remote_user = request.env['REMOTE_USER']
|
9
|
+
remote_password = request.env['REMOTE_PASSWORD']
|
10
|
+
puts "remote_user: #{remote_user}."
|
11
|
+
puts "remote_password: #{remote_password}."
|
12
|
+
identity = basic_authentication(data_provider, remote_user, remote_password, no_cache)
|
13
|
+
identity = basic_authentication(data_provider, remote_user, remote_password, true) unless identity and identity.valid?
|
14
|
+
end
|
15
|
+
|
16
|
+
def basic_authentication data_provider, remote_user, remote_password, no_cache=false
|
17
|
+
identity, assume_identity = parse_identities(remote_user, remote_password)
|
18
|
+
puts "identity: #{identity}"
|
19
|
+
puts "assume_identity: #{assume_identity}"
|
20
|
+
valid = false
|
21
|
+
identity = authenticate_identity(data_provider, identity, no_cache)
|
22
|
+
identity = authorize_identity(data_provider, identity, no_cache)
|
23
|
+
assume_identity = authenticate_identity(assume_identity, no_cache) if assume_identity and identity and identity.valid?
|
24
|
+
assume_identity = authorize_identity(data_provider, assume_identity, no_cache) if assume_identity
|
25
|
+
valid = (assume_identity and assume_identity.valid?) or (identity and identity.valid?)
|
26
|
+
return assume_identity if assume_identity
|
27
|
+
identity
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_identities remote_user, remote_password
|
31
|
+
identity = JunglePath::Authentication::Identity.new
|
32
|
+
identity.remote_user = remote_user
|
33
|
+
identity.remote_password = remote_password
|
34
|
+
assume_identity = nil
|
35
|
+
if remote_user and remote_user.include?("|")
|
36
|
+
parts = remote_user.split('|')
|
37
|
+
identity.user_name = parts[1]
|
38
|
+
assume_identity = JunglePath::Authentication::Identity.new
|
39
|
+
assume_identity.user_name = parts[0]
|
40
|
+
assume_identity.remote_user = remote_user
|
41
|
+
assume_identity.remote_password = remote_password
|
42
|
+
else
|
43
|
+
identity.user_name = remote_user
|
44
|
+
end
|
45
|
+
return identity, assume_identity
|
46
|
+
end
|
47
|
+
|
48
|
+
def authenticate_identity data_provider, identity, no_cache=false
|
49
|
+
id = nil
|
50
|
+
if identity
|
51
|
+
id = identity.dup
|
52
|
+
id.user = data_provider.get_user(identity.user_name, identity.remote_password, no_cache)
|
53
|
+
id.key = id.user
|
54
|
+
id.valid = (id.user and id.user.is_valid)
|
55
|
+
end
|
56
|
+
id
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize_identity data_provider, identity, no_cache
|
60
|
+
id = nil
|
61
|
+
if identity
|
62
|
+
id = identity.dup
|
63
|
+
if id.valid?
|
64
|
+
id.roles = data_provider.get_roles(id, no_cache)
|
65
|
+
id.default_role = id.roles[0] if id.roles
|
66
|
+
id.auth = data_provider.get_auth(id, no_cache)
|
67
|
+
id.user.auth = id.auth if id.user
|
68
|
+
id.query_filters = data_provider.get_query_filters(id, no_cache)
|
69
|
+
else
|
70
|
+
id.roles = nil
|
71
|
+
id.default_role = nil
|
72
|
+
id.auth = nil
|
73
|
+
id.user.auth = nil if id.user
|
74
|
+
id.query_filters = nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
id
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module JunglePath
|
2
|
+
require 'jungle_path/authorization/filter'
|
3
|
+
module Authentication
|
4
|
+
module DataProvider
|
5
|
+
class Default
|
6
|
+
def initialize models_hash
|
7
|
+
@roles = {
|
8
|
+
root: {
|
9
|
+
id: 0,
|
10
|
+
name: :root,
|
11
|
+
description: 'root can do anything',
|
12
|
+
permissions: [:root],
|
13
|
+
restrictions: []
|
14
|
+
},
|
15
|
+
admin: {
|
16
|
+
id: 1,
|
17
|
+
name: :admin,
|
18
|
+
description: 'admin and add, edit and delete users, but not root users.',
|
19
|
+
permissions: [:admin],
|
20
|
+
restrictions: []
|
21
|
+
},
|
22
|
+
user: {
|
23
|
+
id: 2,
|
24
|
+
name: :user,
|
25
|
+
description: 'basic system user -- has read only access.',
|
26
|
+
permissions: [:read],
|
27
|
+
restrictions: [:query_only, :me_related]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
@users = {
|
31
|
+
root: {
|
32
|
+
id: 0,
|
33
|
+
name: 'root',
|
34
|
+
email: nil,
|
35
|
+
phone: nil,
|
36
|
+
active: true,
|
37
|
+
user_name: :root,
|
38
|
+
password: 'test',
|
39
|
+
roles: [:root]
|
40
|
+
},
|
41
|
+
admin: {
|
42
|
+
id: 1,
|
43
|
+
name: 'admin',
|
44
|
+
email: nil,
|
45
|
+
phone: nil,
|
46
|
+
active: true,
|
47
|
+
user_name: :admin,
|
48
|
+
password: 'test',
|
49
|
+
roles: [:admin]
|
50
|
+
},
|
51
|
+
user: {
|
52
|
+
id: 2,
|
53
|
+
name: 'user',
|
54
|
+
email: nil,
|
55
|
+
phone: nil,
|
56
|
+
active: true,
|
57
|
+
user_name: :user,
|
58
|
+
password: 'test',
|
59
|
+
roles: [:user]
|
60
|
+
}
|
61
|
+
}
|
62
|
+
@models = models_hash # (parameter models_hash usually from Schema::Base.models)
|
63
|
+
@role_permissions = {}
|
64
|
+
@role_restrictions = {}
|
65
|
+
@roles.each do |role|
|
66
|
+
@role_permissions[role.name] = role.permissions
|
67
|
+
@role_restrictions[role.name] = role.role_restrictions
|
68
|
+
end
|
69
|
+
@role_schema_filters = lambda {|identity|
|
70
|
+
filters = {
|
71
|
+
root: :allow_all_tables,
|
72
|
+
admin: :allow_all_tables,
|
73
|
+
user: :hide_nonpublic_tables
|
74
|
+
}
|
75
|
+
}
|
76
|
+
@schema_filters = lambda {|identity|
|
77
|
+
filters = {
|
78
|
+
allow_all_tables: {allow: [table: /./]},
|
79
|
+
hide_nonpublic_tables: {allow: [{table: /./}], deny: [{table: /^utility_/}, {table: /^temp_/}]}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
@role_query_filters = lambda {|identity|
|
83
|
+
filters = {
|
84
|
+
admin: [
|
85
|
+
{table_name: :table_i_want_to_filter, sub_select: "select id from table_i_want_to_filter where a = b"}
|
86
|
+
]
|
87
|
+
# more...
|
88
|
+
}
|
89
|
+
}
|
90
|
+
@restriction_query_filters = lambda {|identity|
|
91
|
+
filters = {
|
92
|
+
me_related:[
|
93
|
+
{table_name: :user, sub_select: "select id from user where id = #{identity.user.id}"}
|
94
|
+
]
|
95
|
+
}
|
96
|
+
}
|
97
|
+
@user_query_filters = lambda {|identity|
|
98
|
+
filters = {}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_user(user_name, password, no_cache=false)
|
103
|
+
lower_case_user_name = nil
|
104
|
+
lower_case_user_name = user_name.downcase.to_sym if user_name
|
105
|
+
hash = @users[lower_case_user_name]
|
106
|
+
user = JunglePath::Schema::User.new(hash, false) if hash
|
107
|
+
halt 401, "Unauthorized" unless user
|
108
|
+
halt 401, "Unauthorized: user #{user.user_name} is not marked as active." unless user.active
|
109
|
+
user.is_valid = (user.password == password)
|
110
|
+
user.password = password
|
111
|
+
user
|
112
|
+
end
|
113
|
+
|
114
|
+
def get_roles(identity, no_cache=false)
|
115
|
+
result = []
|
116
|
+
roles = @users[identity.user.user_name.to_sym].roles
|
117
|
+
roles.each do |role_symbol|
|
118
|
+
role = @roles[role_symbol]
|
119
|
+
result << ({id: role[:id], name: role[:name], description: role[:description]})
|
120
|
+
end
|
121
|
+
result
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_auth(identity, no_cache=false)
|
125
|
+
auth = JunglePath::Authorization::Filter.new(identity.roles, @models, @role_permissions, @role_restrictions, @role_schema_filters.call(identity), @schema_filters.call(identity))
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_query_filters(identity, no_cache=false)
|
129
|
+
filters = []
|
130
|
+
@role_query_filters.call(identity).each do |filter|
|
131
|
+
filters << filter
|
132
|
+
end
|
133
|
+
@restriction_query_filters.call(identity).each do |filter|
|
134
|
+
filters << filter
|
135
|
+
end
|
136
|
+
@user_query_filters.call(identity).each do |filter|
|
137
|
+
filters << filter
|
138
|
+
end
|
139
|
+
filters
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module JunglePath
|
4
|
+
module Authentication
|
5
|
+
module Helpers
|
6
|
+
def self.generate_api_key(prefix="sk_")
|
7
|
+
begin
|
8
|
+
key = SecureRandom.urlsafe_base64(18)
|
9
|
+
end while key.include? ?_
|
10
|
+
key = prefix + key
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.expires_in_timestamp(days: 0, hours: 0, minutes: 0, seconds: 0)
|
14
|
+
s = seconds + (minutes * 60) + (hours * 60 * 60) + (days * 24 * 60 * 60)
|
15
|
+
expires_timestamp = Time.new + s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module JunglePath
|
2
|
+
module Authentication
|
3
|
+
class Identity
|
4
|
+
attr_accessor :remote_user, :remote_password, :user_name, :user, :key, :valid, :roles, :default_role, :auth, :query_filters
|
5
|
+
def to_s
|
6
|
+
"JunglePath::Authentication::Identity: {\n remote_user: #{@remote_user},\n remote_password: #{@remote_password},\n user_name: #{@user_name},\n user: #{@user},\n key: #{@key},\n valid: #{@valid},\n roles: #{@roles},\n auth: #{@auth}\n,query_filters: #{@query_filters}\n}"
|
7
|
+
end
|
8
|
+
def to_h
|
9
|
+
{
|
10
|
+
remote_user: @remote_user,
|
11
|
+
remote_password: @remote_password,
|
12
|
+
user_name: @user_name,
|
13
|
+
user: @user,
|
14
|
+
key: @key,
|
15
|
+
valid: @valid,
|
16
|
+
roles: @roles,
|
17
|
+
default_role: @default_role,
|
18
|
+
auth: @auth,
|
19
|
+
query_filters: @query_filters
|
20
|
+
}
|
21
|
+
end
|
22
|
+
def to_hash
|
23
|
+
to_h
|
24
|
+
end
|
25
|
+
def valid?
|
26
|
+
@valid
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# https://crackstation.net/hashing-security.htm#rubysourcecode
|
2
|
+
# Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
|
3
|
+
# Copyright (c) 2013, Taylor Hornby
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
17
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
18
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
20
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
28
|
+
# Changed 2017-03-30:
|
29
|
+
# I wrapped this in jungle_path gem...
|
30
|
+
require 'securerandom'
|
31
|
+
require 'openssl'
|
32
|
+
require 'base64'
|
33
|
+
|
34
|
+
module JunglePath
|
35
|
+
module Authentication
|
36
|
+
|
37
|
+
# Salted password hashing with PBKDF2-SHA1.
|
38
|
+
# Authors: @RedragonX (dicesoft.net), havoc AT defuse.ca
|
39
|
+
# www: http://crackstation.net/hashing-security.htm
|
40
|
+
module PasswordHash
|
41
|
+
|
42
|
+
# The following constants can be changed without breaking existing hashes.
|
43
|
+
PBKDF2_ITERATIONS = 1000
|
44
|
+
SALT_BYTE_SIZE = 24
|
45
|
+
HASH_BYTE_SIZE = 24
|
46
|
+
|
47
|
+
HASH_SECTIONS = 4
|
48
|
+
SECTION_DELIMITER = ':'
|
49
|
+
ITERATIONS_INDEX = 1
|
50
|
+
SALT_INDEX = 2
|
51
|
+
HASH_INDEX = 3
|
52
|
+
|
53
|
+
# Returns a salted PBKDF2 hash of the password.
|
54
|
+
def self.createHash( password )
|
55
|
+
salt = SecureRandom.base64( SALT_BYTE_SIZE )
|
56
|
+
pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
|
57
|
+
password,
|
58
|
+
salt,
|
59
|
+
PBKDF2_ITERATIONS,
|
60
|
+
HASH_BYTE_SIZE
|
61
|
+
)
|
62
|
+
return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checks if a password is correct given a hash of the correct one.
|
66
|
+
# correctHash must be a hash string generated with createHash.
|
67
|
+
def self.validatePassword( password, correctHash )
|
68
|
+
params = correctHash.split( SECTION_DELIMITER )
|
69
|
+
return false if params.length != HASH_SECTIONS
|
70
|
+
|
71
|
+
pbkdf2 = Base64.decode64( params[HASH_INDEX] )
|
72
|
+
testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
|
73
|
+
password,
|
74
|
+
params[SALT_INDEX],
|
75
|
+
params[ITERATIONS_INDEX].to_i,
|
76
|
+
pbkdf2.length
|
77
|
+
)
|
78
|
+
|
79
|
+
return pbkdf2 == testHash
|
80
|
+
end
|
81
|
+
|
82
|
+
# Run tests to ensure the module is functioning properly.
|
83
|
+
# Returns true if all tests succeed, false if not.
|
84
|
+
def self.runSelfTests
|
85
|
+
puts "Sample hashes:"
|
86
|
+
3.times { puts createHash("password") }
|
87
|
+
|
88
|
+
puts "\nRunning self tests..."
|
89
|
+
@@allPass = true
|
90
|
+
|
91
|
+
correctPassword = 'aaaaaaaaaa'
|
92
|
+
wrongPassword = 'aaaaaaaaab'
|
93
|
+
hash = createHash(correctPassword)
|
94
|
+
|
95
|
+
assert( validatePassword( correctPassword, hash ) == true, "correct password" )
|
96
|
+
assert( validatePassword( wrongPassword, hash ) == false, "wrong password" )
|
97
|
+
|
98
|
+
h1 = hash.split( SECTION_DELIMITER )
|
99
|
+
h2 = createHash( correctPassword ).split( SECTION_DELIMITER )
|
100
|
+
assert( h1[HASH_INDEX] != h2[HASH_INDEX], "different hashes" )
|
101
|
+
assert( h1[SALT_INDEX] != h2[SALT_INDEX], "different salt" )
|
102
|
+
|
103
|
+
if @@allPass
|
104
|
+
puts "*** ALL TESTS PASS ***"
|
105
|
+
else
|
106
|
+
puts "*** FAILURES ***"
|
107
|
+
end
|
108
|
+
|
109
|
+
return @@allPass
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.assert( truth, msg )
|
113
|
+
if truth
|
114
|
+
puts "PASS [#{msg}]"
|
115
|
+
else
|
116
|
+
puts "FAIL [#{msg}]"
|
117
|
+
@@allPass = false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
#PasswordHash.runSelfTests
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module JunglePath
|
2
|
+
module Authentication
|
3
|
+
require 'jungle_path/authentication/auth_provider'
|
4
|
+
require 'jungle_path/authentication/data_provider'
|
5
|
+
require 'jungle_path/authentication/helpers'
|
6
|
+
require 'jungle_path/authentication/identity'
|
7
|
+
require 'jungle_path/authentication/password_hash'
|
8
|
+
end
|
9
|
+
end
|