ixtlan-user-management 0.2.0 → 0.3.1
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.
- data/lib/ixtlan/user_management/dummy_authentication.rb +3 -3
- data/lib/ixtlan/user_management/group_model.rb +2 -2
- data/lib/ixtlan/user_management/guard.rb +40 -14
- data/lib/ixtlan/user_management/permission_model.rb +45 -8
- data/lib/ixtlan/user_management/session_serializer.rb +16 -13
- data/lib/ixtlan/user_management/user_serializer.rb +6 -9
- data/spec/guard_spec.rb +24 -4
- data/spec/session_manager_spec.rb +2 -2
- data/spec/session_serializer_spec.rb +104 -39
- metadata +18 -2
@@ -58,13 +58,13 @@ module Ixtlan
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def group_for( model, login )
|
61
|
-
model.new('name' => login.sub( /\[.*/, '' ) )
|
61
|
+
model.new('name' => login.sub( /\[.*/, '' ), 'associations'=> split( login ) )
|
62
62
|
end
|
63
63
|
|
64
64
|
def split( login )
|
65
|
-
login.sub( /.*\[/ , '' ).sub( /\].*/, '' ).split( /,/ )
|
65
|
+
login.sub( /.*\[/ , '' ).sub( /\].*/, '' ).split( /,/ ) if login.match /.+\[/
|
66
66
|
end
|
67
67
|
|
68
68
|
end
|
69
69
|
end
|
70
|
-
end
|
70
|
+
end
|
@@ -29,32 +29,58 @@ module Ixtlan
|
|
29
29
|
:delete => 'delete'
|
30
30
|
}
|
31
31
|
|
32
|
-
def allow?( resource
|
33
|
-
|
34
|
-
|
35
|
-
perm.associations.
|
36
|
-
|
32
|
+
def allow?( resource, method, association = nil )
|
33
|
+
perms = permissions[ resource ] || []
|
34
|
+
perms.one? do |perm|
|
35
|
+
( perm.associations.nil? ||
|
36
|
+
perm.associations.include?( association.to_s ) ) &&
|
37
|
+
perm.allow?( METHODS[ method ], association )
|
38
|
+
end
|
37
39
|
end
|
38
40
|
|
39
|
-
def associations( resource, method )
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
def associations( resource, method = nil )
|
42
|
+
perms = permissions[ resource ] || []
|
43
|
+
asso = perms.select { |perm| perm.associations }
|
44
|
+
if asso.empty?
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
asso.collect{ |perm| perm.associations }.flatten
|
43
48
|
end
|
44
49
|
# TODO method
|
45
50
|
end
|
46
51
|
|
52
|
+
def check_parent( resource, parent_resource )
|
53
|
+
perms = permissions[ resource ]
|
54
|
+
if perms
|
55
|
+
perms.each do |perm|
|
56
|
+
if perm.parent && perm.parent.resource != parent_resource
|
57
|
+
raise 'parent resource is not guarded'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
47
63
|
def all_permissions
|
48
|
-
|
64
|
+
permissions.values.flatten.select { |pp| pp.parent.nil? }
|
49
65
|
end
|
50
66
|
|
51
|
-
def permissions
|
67
|
+
def permissions
|
52
68
|
@permissions ||= {}
|
53
|
-
|
69
|
+
end
|
70
|
+
|
71
|
+
def permissions_new( resource )
|
72
|
+
pp = Permission.new( :resource => resource )
|
73
|
+
( permissions[ resource ] ||= [] ) << pp
|
74
|
+
pp
|
54
75
|
end
|
55
76
|
|
56
|
-
def
|
57
|
-
current =
|
77
|
+
def permission_for( resource, *associations, &block )
|
78
|
+
current = permissions_new( resource )
|
79
|
+
associations.flatten!
|
80
|
+
if associations.first.is_a? Permission
|
81
|
+
current.parent = associations.first
|
82
|
+
associations = associations[ 1..-1 ]
|
83
|
+
end
|
58
84
|
current.associations = associations unless associations.empty?
|
59
85
|
block.call current if block
|
60
86
|
current
|
@@ -26,7 +26,7 @@ module Ixtlan
|
|
26
26
|
|
27
27
|
attribute :verb, String
|
28
28
|
attribute :name, String
|
29
|
-
|
29
|
+
attribute :associations, Array[String], :default => nil
|
30
30
|
end
|
31
31
|
class Permission
|
32
32
|
include Virtus
|
@@ -36,40 +36,77 @@ module Ixtlan
|
|
36
36
|
:allow_update,
|
37
37
|
:allow_delete ]
|
38
38
|
|
39
|
+
attribute :parent, Permission
|
40
|
+
attribute :children, Array[Permission]
|
39
41
|
attribute :resource, String
|
40
42
|
attribute :actions, Array[Action], :default => []
|
41
43
|
attribute :allow, Boolean, :default => true
|
42
|
-
attribute :associations, Array[String]
|
43
|
-
|
44
|
-
def
|
44
|
+
attribute :associations, Array[String], :default => nil
|
45
|
+
|
46
|
+
def parent=( pt )
|
47
|
+
super
|
48
|
+
if pt
|
49
|
+
pt.children << self
|
50
|
+
elsif parent
|
51
|
+
parent.children.delete self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def allow?( method, association = nil )
|
45
56
|
action = self.actions.detect { |a| a.name == method }
|
46
57
|
if self.allow
|
47
|
-
|
58
|
+
action != nil && ( action.associations.nil? || action.associations.include?( association ) )
|
48
59
|
else
|
49
60
|
action.nil? #TODO associations
|
50
61
|
end
|
51
62
|
end
|
52
63
|
|
53
|
-
def allow_all
|
64
|
+
def allow_all( *associations )
|
54
65
|
self.allow = false
|
55
66
|
self.actions.clear
|
67
|
+
set_asso( self, *associations )
|
68
|
+
self
|
56
69
|
end
|
57
70
|
|
71
|
+
def set_asso( obj, *associations )
|
72
|
+
case associations.first
|
73
|
+
when NilClass
|
74
|
+
# leave default
|
75
|
+
when Array
|
76
|
+
# assume empty
|
77
|
+
obj.associations = associations.flatten
|
78
|
+
else
|
79
|
+
obj.associations = associations
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
58
83
|
def deny_all
|
59
84
|
self.allow = true
|
60
85
|
self.actions.clear
|
86
|
+
self
|
61
87
|
end
|
62
88
|
|
63
89
|
def allow_mutate( *associations )
|
64
90
|
allow_retrieve( *associations )
|
65
91
|
allow_create( *associations )
|
66
92
|
allow_update( *associations )
|
93
|
+
self
|
67
94
|
end
|
68
95
|
|
69
96
|
def method_missing( method, *args )
|
70
97
|
if METHODS.include?( method )
|
71
|
-
|
72
|
-
|
98
|
+
a = Action.new( :name => method.to_s.sub( /allow_/, '' ) )
|
99
|
+
set_asso( a, *args )
|
100
|
+
self.actions << a
|
101
|
+
self
|
102
|
+
elsif METHODS.include?( method.to_s.sub( /_verb$/, '' ).to_sym )
|
103
|
+
verb = args.first
|
104
|
+
args = args[ 1..-1 ]
|
105
|
+
a = Action.new( :name => method.to_s.gsub( /allow_|_verb/, '' ),
|
106
|
+
:verb => verb )
|
107
|
+
set_asso( a, *args )
|
108
|
+
self.actions << a
|
109
|
+
self
|
73
110
|
else
|
74
111
|
super
|
75
112
|
end
|
@@ -25,19 +25,22 @@ module Ixtlan
|
|
25
25
|
|
26
26
|
root 'session'
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
28
|
+
PERM = [ :resource,
|
29
|
+
:allow,
|
30
|
+
:associations ]
|
31
|
+
ACTION = only( :name,
|
32
|
+
:verb,
|
33
|
+
:associations )
|
34
|
+
|
35
|
+
add_context( :single ) do
|
36
|
+
only( :idle_session_timeout,
|
37
|
+
:user => only( :id, :login, :name ),
|
38
|
+
:permissions => only( PERM,
|
39
|
+
:actions => ACTION,
|
40
|
+
:children => only( PERM,
|
41
|
+
:actions => ACTION ) ) )
|
42
|
+
|
43
|
+
end
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
@@ -23,15 +23,12 @@ module Ixtlan
|
|
23
23
|
module UserManagement
|
24
24
|
class UserSerializer < Ixtlan::Babel::Serializer
|
25
25
|
|
26
|
-
add_context(:session
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:methods => [:name]
|
33
|
-
}
|
34
|
-
})
|
26
|
+
add_context( :session ) do
|
27
|
+
only( :login,
|
28
|
+
:name,
|
29
|
+
:groups => only( :name,
|
30
|
+
:associations ) )
|
31
|
+
end
|
35
32
|
end
|
36
33
|
end
|
37
34
|
end
|
data/spec/guard_spec.rb
CHANGED
@@ -22,7 +22,7 @@ describe Ixtlan::UserManagement::Guard do
|
|
22
22
|
|
23
23
|
before do
|
24
24
|
%w( audits errors configuration ).each do |resource|
|
25
|
-
subject.
|
25
|
+
subject.permission_for( resource ).deny_all
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -79,7 +79,7 @@ describe Ixtlan::UserManagement::Guard do
|
|
79
79
|
%w( audits errors configuration ).each do |resource|
|
80
80
|
[ 'domain', nil ].each do |asso|
|
81
81
|
expected = Ixtlan::UserManagement::Guard::METHODS[ m ]
|
82
|
-
subject.allow?( resource, m, asso ).must_equal
|
82
|
+
subject.allow?( resource, m, asso ).must_equal(expected == meth)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -90,8 +90,27 @@ describe Ixtlan::UserManagement::Guard do
|
|
90
90
|
p.send method
|
91
91
|
p.associations = [ 'domain', 'nodomain' ]
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
|
+
[ :get, :post, :put, :delete ].each do |m|
|
95
|
+
%w( audits errors configuration ).each do |resource|
|
96
|
+
[ 'something', nil ].each do |asso|
|
97
|
+
subject.allow?( resource, m, asso ).must_equal false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
94
101
|
meth = method.to_s.sub( /allow_/, '' )
|
102
|
+
[ :get, :post, :put, :delete ].each do |m|
|
103
|
+
%w( audits errors configuration ).each do |resource|
|
104
|
+
expected = Ixtlan::UserManagement::Guard::METHODS[ m ]
|
105
|
+
subject.allow?( resource, m, 'domain' ).must_equal(expected == meth)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
it "#{method.to_s.sub( /_/, 's ')} with action with associations" do
|
110
|
+
subject.all_permissions.each do |p|
|
111
|
+
p.send method, 'domain', 'nodomain'
|
112
|
+
end
|
113
|
+
|
95
114
|
[ :get, :post, :put, :delete ].each do |m|
|
96
115
|
%w( audits errors configuration ).each do |resource|
|
97
116
|
[ 'something', nil ].each do |asso|
|
@@ -99,10 +118,11 @@ describe Ixtlan::UserManagement::Guard do
|
|
99
118
|
end
|
100
119
|
end
|
101
120
|
end
|
121
|
+
meth = method.to_s.sub( /allow_/, '' )
|
102
122
|
[ :get, :post, :put, :delete ].each do |m|
|
103
123
|
%w( audits errors configuration ).each do |resource|
|
104
124
|
expected = Ixtlan::UserManagement::Guard::METHODS[ m ]
|
105
|
-
subject.allow?( resource, m, 'domain' ).must_equal
|
125
|
+
subject.allow?( resource, m, 'domain' ).must_equal(expected == meth)
|
106
126
|
end
|
107
127
|
end
|
108
128
|
end
|
@@ -25,8 +25,8 @@ describe Ixtlan::UserManagement::SessionManager do
|
|
25
25
|
expected = {
|
26
26
|
"login"=>"root",
|
27
27
|
"name"=>"Root",
|
28
|
-
"groups"=>[{"name"=>"root"},
|
29
|
-
{"name"=>"admin"}]
|
28
|
+
"groups"=>[{"name"=>"root", "associations"=>nil},
|
29
|
+
{"name"=>"admin", "associations"=>nil}]
|
30
30
|
}
|
31
31
|
|
32
32
|
data = subject.to_session( user )
|
@@ -43,9 +43,57 @@ describe Ixtlan::UserManagement::Session do
|
|
43
43
|
result.must_equal expected
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'serializes with associations' do
|
47
|
+
guard.permission_for( 'audits' ).allow_all( 12,123 )
|
48
|
+
|
49
|
+
subject.permissions = guard.all_permissions
|
50
|
+
|
51
|
+
expected = {
|
52
|
+
"session"=>{"idle_session_timeout"=>30,
|
53
|
+
"user"=>{
|
54
|
+
"id"=>1,
|
55
|
+
"login"=>"root",
|
56
|
+
"name"=>"Root"
|
57
|
+
},
|
58
|
+
"permissions"=>[{ "children" => [],
|
59
|
+
"resource"=>"audits",
|
60
|
+
"actions"=>[],
|
61
|
+
"allow"=>false,
|
62
|
+
"associations"=>["12", "123"]}]
|
63
|
+
}
|
64
|
+
}
|
65
|
+
result = factory.new_serializer( subject ).to_hash
|
66
|
+
result.must_equal expected
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'serializes with empty associations' do
|
70
|
+
guard.permission_for( 'audits' ).allow_retrieve( [] )
|
71
|
+
|
72
|
+
subject.permissions = guard.all_permissions
|
73
|
+
|
74
|
+
expected = {
|
75
|
+
"session"=>{"idle_session_timeout"=>30,
|
76
|
+
"user"=>{
|
77
|
+
"id"=>1,
|
78
|
+
"login"=>"root",
|
79
|
+
"name"=>"Root"
|
80
|
+
},
|
81
|
+
"permissions"=>[{ "children" => [],
|
82
|
+
"resource"=>"audits",
|
83
|
+
"actions"=>[{ "verb"=>nil,
|
84
|
+
"name"=>"retrieve",
|
85
|
+
"associations"=>[] }],
|
86
|
+
"allow"=>true,
|
87
|
+
"associations"=>nil}]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
result = factory.new_serializer( subject ).to_hash
|
91
|
+
result.must_equal expected
|
92
|
+
end
|
93
|
+
|
46
94
|
it 'serializes with root permissions' do
|
47
95
|
%w( audits errors configuration ).each do |resource|
|
48
|
-
guard.
|
96
|
+
guard.permission_for( resource ).allow_all
|
49
97
|
end
|
50
98
|
|
51
99
|
subject.permissions = guard.all_permissions
|
@@ -57,18 +105,21 @@ describe Ixtlan::UserManagement::Session do
|
|
57
105
|
"login"=>"root",
|
58
106
|
"name"=>"Root"
|
59
107
|
},
|
60
|
-
"permissions"=>[{"
|
108
|
+
"permissions"=>[{ "children" => [],
|
109
|
+
"resource"=>"audits",
|
61
110
|
"actions"=>[],
|
62
111
|
"allow"=>false,
|
63
|
-
"associations"=>
|
64
|
-
{"
|
112
|
+
"associations"=>nil},
|
113
|
+
{ "children" => [],
|
114
|
+
"resource"=>"errors",
|
65
115
|
"actions"=>[],
|
66
116
|
"allow"=>false,
|
67
|
-
"associations"=>
|
68
|
-
{"
|
117
|
+
"associations"=>nil},
|
118
|
+
{ "children" => [],
|
119
|
+
"resource"=>"configuration",
|
69
120
|
"actions"=>[],
|
70
121
|
"allow"=>false,
|
71
|
-
"associations"=>
|
122
|
+
"associations"=>nil}
|
72
123
|
]
|
73
124
|
}
|
74
125
|
}
|
@@ -77,10 +128,10 @@ describe Ixtlan::UserManagement::Session do
|
|
77
128
|
end
|
78
129
|
|
79
130
|
it 'serializes with some permissions' do
|
80
|
-
guard.
|
81
|
-
guard.
|
82
|
-
guard.
|
83
|
-
guard.
|
131
|
+
guard.permission_for( 'audits' ).allow_retrieve
|
132
|
+
guard.permission_for( 'errors' ).allow_create
|
133
|
+
guard.permission_for( 'configuration' ).allow_update
|
134
|
+
guard.permission_for( 'users' ).allow_delete
|
84
135
|
|
85
136
|
subject.permissions = guard.all_permissions
|
86
137
|
|
@@ -91,26 +142,34 @@ describe Ixtlan::UserManagement::Session do
|
|
91
142
|
"login"=>"root",
|
92
143
|
"name"=>"Root"
|
93
144
|
},
|
94
|
-
"permissions"=>[{"
|
95
|
-
"
|
96
|
-
|
145
|
+
"permissions"=>[{ "children" => [],
|
146
|
+
"resource"=>"audits",
|
147
|
+
"actions"=>[{ "verb" => nil,
|
148
|
+
"name"=>"retrieve",
|
149
|
+
"associations"=>nil}],
|
97
150
|
"allow"=>true,
|
98
|
-
"associations"=>
|
99
|
-
{"
|
100
|
-
"
|
101
|
-
|
151
|
+
"associations"=>nil},
|
152
|
+
{ "children" => [],
|
153
|
+
"resource"=>"errors",
|
154
|
+
"actions"=>[{ "verb" => nil,
|
155
|
+
"name"=>"create",
|
156
|
+
"associations"=>nil}],
|
102
157
|
"allow"=>true,
|
103
|
-
"associations"=>
|
104
|
-
{"
|
105
|
-
"
|
106
|
-
|
158
|
+
"associations"=>nil},
|
159
|
+
{ "children" => [],
|
160
|
+
"resource"=>"configuration",
|
161
|
+
"actions"=>[{ "verb" => nil,
|
162
|
+
"name"=>"update",
|
163
|
+
"associations"=>nil}],
|
107
164
|
"allow"=>true,
|
108
|
-
"associations"=>
|
109
|
-
{"
|
110
|
-
"
|
111
|
-
|
165
|
+
"associations"=>nil},
|
166
|
+
{ "children" => [],
|
167
|
+
"resource"=>"users",
|
168
|
+
"actions"=>[{ "verb" => nil,
|
169
|
+
"name"=>"delete",
|
170
|
+
"associations"=>nil}],
|
112
171
|
"allow"=>true,
|
113
|
-
"associations"=>
|
172
|
+
"associations"=>nil}
|
114
173
|
]
|
115
174
|
}
|
116
175
|
}
|
@@ -119,8 +178,8 @@ describe Ixtlan::UserManagement::Session do
|
|
119
178
|
end
|
120
179
|
|
121
180
|
it 'serializes permissions with assoications' do
|
122
|
-
guard.
|
123
|
-
guard.
|
181
|
+
guard.permission_for( 'audits', 'domain' ).allow_mutate
|
182
|
+
guard.permission_for( 'users', 'nodomain', 'domain' ).allow_delete
|
124
183
|
|
125
184
|
subject.permissions = guard.all_permissions
|
126
185
|
|
@@ -131,18 +190,24 @@ describe Ixtlan::UserManagement::Session do
|
|
131
190
|
"login"=>"root",
|
132
191
|
"name"=>"Root"
|
133
192
|
},
|
134
|
-
"permissions"=>[{"
|
135
|
-
"
|
136
|
-
|
137
|
-
|
138
|
-
"
|
139
|
-
{"verb"=>nil,
|
140
|
-
"name"=>"
|
193
|
+
"permissions"=>[{ "children" => [],
|
194
|
+
"resource"=>"audits",
|
195
|
+
"actions"=>[{ "verb" => nil,
|
196
|
+
"name"=>"retrieve",
|
197
|
+
"associations"=>nil},
|
198
|
+
{ "verb" => nil,
|
199
|
+
"name"=>"create",
|
200
|
+
"associations"=>nil},
|
201
|
+
{ "verb" => nil,
|
202
|
+
"name"=>"update",
|
203
|
+
"associations"=>nil}],
|
141
204
|
"allow"=>true,
|
142
205
|
"associations"=>["domain"]},
|
143
|
-
{"
|
144
|
-
"
|
145
|
-
|
206
|
+
{ "children" => [],
|
207
|
+
"resource"=>"users",
|
208
|
+
"actions"=>[{ "verb" => nil,
|
209
|
+
"name"=>"delete",
|
210
|
+
"associations"=>nil}],
|
146
211
|
"allow"=>true,
|
147
212
|
"associations"=>["nodomain", "domain"]}
|
148
213
|
]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ixtlan-user-management
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -219,6 +219,22 @@ dependencies:
|
|
219
219
|
none: false
|
220
220
|
prerelease: false
|
221
221
|
type: :development
|
222
|
+
- !ruby/object:Gem::Dependency
|
223
|
+
name: ixtlan-babel
|
224
|
+
version_requirements: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - '>='
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: '0'
|
229
|
+
none: false
|
230
|
+
requirement: !ruby/object:Gem::Requirement
|
231
|
+
requirements:
|
232
|
+
- - '>='
|
233
|
+
- !ruby/object:Gem::Version
|
234
|
+
version: '0'
|
235
|
+
none: false
|
236
|
+
prerelease: false
|
237
|
+
type: :development
|
222
238
|
- !ruby/object:Gem::Dependency
|
223
239
|
name: json
|
224
240
|
version_requirements: !ruby/object:Gem::Requirement
|