ixtlan-user-management 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|