Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Bee-color framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Operations
Operations
Incidents
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jordan Breton
Bee-color framework
Commits
e976758f
Commit
e976758f
authored
Aug 11, 2019
by
Jordan Breton
✏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP Commands security
parent
cdc068e4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
311 additions
and
2 deletions
+311
-2
engine/core/command/security/rules/NotCommandAccessRule.php
engine/core/command/security/rules/NotCommandAccessRule.php
+32
-0
engine/core/command/security/rules/UserTypeBasedCommandAccessRule.php
...command/security/rules/UserTypeBasedCommandAccessRule.php
+184
-0
engine/core/security/WFWDefaultSecurityPolicy.php
engine/core/security/WFWDefaultSecurityPolicy.php
+52
-1
engine/package/lang/security/LangAccessControlPolicies.php
engine/package/lang/security/LangAccessControlPolicies.php
+3
-1
engine/package/uploader/security/UploaderAccessControlPolicies.php
...ckage/uploader/security/UploaderAccessControlPolicies.php
+10
-0
engine/package/users/security/UsersAccessControlPolicies.php
engine/package/users/security/UsersAccessControlPolicies.php
+30
-0
No files found.
engine/core/command/security/rules/NotCommandAccessRule.php
0 → 100644
View file @
e976758f
<?php
namespace
wfw\engine\core\command\security\rules
;
use
wfw\engine\core\command\ICommand
;
/**
* Class NotCommandAccessRule
*
* @package wfw\engine\core\command\security\rules
*/
final
class
NotCommandAccessRule
implements
ICommandAccessRule
{
/** @var ICommandAccessRule $_rule */
private
$_rule
;
/**
* NotCommandAccessRule constructor.
*
* @param ICommandAccessRule $rule Rule to negate
*/
public
function
__construct
(
ICommandAccessRule
$rule
)
{
$this
->
_rule
=
$rule
;
}
/**
* @param ICommand $cmd
* @return null|bool True if the command can be run, false otherwise. Null if not applicable
*/
public
function
checkCommand
(
ICommand
$cmd
):
?bool
{
return
!
$this
->
_rule
->
checkCommand
(
$cmd
);
}
}
\ No newline at end of file
engine/core/command/security/rules/UserTypeBasedCommandAccessRule.php
0 → 100644
View file @
e976758f
<?php
namespace
wfw\engine\core\command\security\rules
;
use
wfw\engine\core\cache\ICacheSystem
;
use
wfw\engine\core\command\ICommand
;
use
wfw\engine\core\command\security\ICommandAccessRuleFactory
;
use
wfw\engine\package\users\data\model\IUserModelAccess
;
use
wfw\engine\package\users\domain\types\Admin
;
use
wfw\engine\package\users\domain\types\UserType
;
/**
* Admin users have all permission, other user only the "any_user" permissions.
* Public commands are made using the "public" (no registration needed) array.
* Some commands can be attributed to the UserType::class => CommandClass[]
* Some specific rules can be attribued to each commands CommandClass => [ ICommandAccessRuleClass => [] ]
* AccessRules will be built and checked accordingly, or loaded from cache.
*
* Example :
* [
* "public" => [], //no public command
* "any_user" => [ ChangePassword::class => [ ICommandAccessRuleClass => []] ],
* Client::class => [ Unregister::class => [] ]
* ]
*/
final
class
UserTypeBasedCommandAccessRule
implements
ICommandAccessRule
{
public
const
CACHE_KEY
=
self
::
class
.
"/results"
;
public
const
ANY
=
"any user"
;
public
const
PUBLIC
=
"public command"
;
/** @var IUserModelAccess $_model */
private
$_model
;
/** @var array|mixed $_cache */
private
$_cache
;
/** @var ICommandAccessRuleFactory $_factory */
private
$_factory
;
/** @var ICacheSystem $_cacheSystem */
private
$_cacheSystem
;
/** @var ICommandAccessRule[][] $_permissions */
private
$_permissions
;
/**
* UserTypeBasedCommandAccessRule constructor.
*
* @param IUserModelAccess $model
* @param ICommandAccessRuleFactory $factory
* @param ICacheSystem $cache
* @param array $permissions
* @throws \InvalidArgumentException
*/
public
function
__construct
(
IUserModelAccess
$model
,
ICommandAccessRuleFactory
$factory
,
ICacheSystem
$cache
,
array
$permissions
=
[]
){
$this
->
_model
=
$model
;
$this
->
_factory
=
$factory
;
$this
->
_permissions
=
$this
->
checkPermissionsFormat
(
$permissions
);
$this
->
_cache
=
$cache
->
get
(
self
::
CACHE_KEY
)
??
[];
$this
->
_cacheSystem
=
$cache
;
}
/**
* @param array $permissions
* @return array
* @throws \InvalidArgumentException
*/
private
function
checkPermissionsFormat
(
array
$permissions
):
array
{
$res
=
$permissions
;
foreach
(
array_keys
(
$permissions
)
as
$key
){
if
(
!
in_array
(
$key
,[
self
::
PUBLIC
,
self
::
ANY
])){
if
(
!
is_a
(
$key
,
UserType
::
class
,
true
))
throw
new
\
InvalidArgumentException
(
"
$key
must implements "
.
UserType
::
class
);
}
}
foreach
(
$permissions
as
$type
=>
$cmds
){
foreach
(
$cmds
as
$cmd
=>
$rules
){
if
(
is_int
(
$cmd
)){
if
(
!
is_string
(
$rules
))
throw
new
\
InvalidArgumentException
(
"In
$type
at offset
$cmd
: value must be a string"
);
$cmdClass
=
$rules
;
}
else
$cmdClass
=
$cmd
;
if
(
!
is_a
(
$cmdClass
,
ICommand
::
class
,
true
))
throw
new
\
InvalidArgumentException
(
"
$cmdClass
must implements "
.
ICommand
::
class
);
if
(
is_array
(
$rules
)){
$rs
=
[];
foreach
(
$rules
as
$class
=>
$params
){
if
(
is_int
(
$class
)){
if
(
is_string
(
$params
))
$rs
[]
=
$this
->
_factory
->
create
(
$params
);
}
else
$rs
[]
=
$this
->
_factory
->
create
(
$params
);
}
if
(
count
(
$rs
)
===
0
)
$res
[
$type
][
$cmd
]
=
new
AllCommandsAllowed
();
else
if
(
count
(
$rs
)
===
1
)
$res
[
$type
][
$cmd
]
=
$rs
[
0
];
else
$res
[
$type
][
$cmd
]
=
new
AndCommandAccessRule
(
...
$rs
);
}
else
if
(
is_bool
(
$rules
))
$res
[
$type
][
$cmd
]
=
$rules
?
new
AllCommandsAllowed
()
:
new
AllCommandsDenied
();
else
$res
[
$type
][
$cmd
]
=
new
AllCommandsAllowed
();
if
(
!
is_array
(
$rules
))
throw
new
\
InvalidArgumentException
(
"
$cmd
rules must be an array"
);
}
}
return
$res
;
}
/**
* @param ICommand $cmd
* @return null|bool True if the command can be run, false otherwise. Null if not applicable
*/
public
function
checkCommand
(
ICommand
$cmd
):
?bool
{
return
$this
->
checkCommandFrom
(
$cmd
,
$this
->
_permissions
);
}
/**
* @param ICommand $cmd
* @param ICommandAccessRule[][] $permissions
* @return bool|null
*/
private
function
checkCommandFrom
(
ICommand
$cmd
,
array
$permissions
):
?bool
{
$cmdClass
=
get_class
(
$cmd
);
if
(
isset
(
$permissions
[
self
::
PUBLIC
][
$cmdClass
]))
return
$permissions
[
self
::
PUBLIC
][
$cmdClass
]
->
checkCommand
(
$cmd
);
/** @var ICommandAccessRule $cached */
$cached
=
$this
->
_cache
[
$cmd
->
getInitiatorId
()][
$cmdClass
]
??
null
;
if
(
!
is_null
(
$cached
))
return
$cached
->
checkCommand
(
$cmd
);
$user
=
$this
->
_model
->
getById
(
$cmd
->
getInitiatorId
());
if
(
!
$user
)
return
false
;
if
(
$user
->
getType
()
instanceof
Admin
)
return
$this
->
setCache
(
$cmd
->
getInitiatorId
(),
$cmdClass
,
new
AllCommandsAllowed
()
)
->
checkCommand
(
$cmd
);
$userTypesClasses
=
array_diff
(
array_keys
(
$permissions
),
[
self
::
PUBLIC
,
self
::
ANY
]
);
foreach
(
$userTypesClasses
as
$userType
){
if
(
is_a
(
$user
->
getType
(),
$userType
)
&&
isset
(
$permissions
[
$userType
][
$cmdClass
])
)
return
$this
->
setCache
(
$cmd
->
getInitiatorId
(),
$cmdClass
,
$permissions
[
$userType
][
$cmdClass
]
)
->
checkCommand
(
$cmd
);
}
//any check
if
(
isset
(
$permissions
[
self
::
ANY
][
$cmdClass
]))
return
$this
->
setCache
(
$cmd
->
getInitiatorId
(),
$cmdClass
,
$permissions
[
self
::
ANY
][
$cmdClass
]
)
->
checkCommand
(
$cmd
);
return
$this
->
setCache
(
$cmd
->
getInitiatorId
(),
$cmdClass
,
new
AllCommandsDenied
()
)
->
checkCommand
(
$cmd
);
}
/**
* Push the result into the cache and return the result
*
* @param string $userId User tested
* @param string $cmdClass Command tested
* @param ICommandAccessRule $res Rule to cache
* @return ICommandAccessRule $res
*/
private
function
setCache
(
string
$userId
,
string
$cmdClass
,
ICommandAccessRule
$res
):
ICommandAccessRule
{
if
(
!
isset
(
$this
->
_cache
[
$userId
]))
$this
->
_cache
[
$userId
]
=
[
$cmdClass
=>
$res
];
else
$this
->
_cache
[
$userId
][
$cmdClass
]
=
$res
;
$this
->
_cacheSystem
->
set
(
self
::
CACHE_KEY
,
$this
->
_cache
);
return
$res
;
}
}
\ No newline at end of file
engine/core/security/WFWDefaultSecurityPolicy.php
View file @
e976758f
...
...
@@ -3,9 +3,11 @@
namespace
wfw\engine\core\security
;
use
wfw\engine\core\action\NotFoundHook
;
use
wfw\engine\core\command\security\rules\UserTypeBasedCommandAccessRule
;
use
wfw\engine\core\security\rules\RequireAuthentification
;
use
wfw\engine\core\security\rules\ValidToken
;
use
wfw\engine\package\general\security\GeneralAccessControlPolicies
;
use
wfw\engine\package\lang\security\LangAccessControlPolicies
;
use
wfw\engine\package\uploader\security\UploaderAccessControlPolicies
;
use
wfw\engine\package\users\security\UsersAccessControlPolicies
;
...
...
@@ -14,6 +16,52 @@ use wfw\engine\package\users\security\UsersAccessControlPolicies;
* if no security have been defined for a project.
*/
final
class
WFWDefaultSecurityPolicy
extends
SecurityPolicy
{
/**
* @param array $policies
* @param bool $includeBase If true, will include default's WFW policies
* @param array $templateArray Template array to specify the query policy order
* @return array
*/
public
static
function
queriesPolicy
(
array
$policies
=
[],
bool
$includeBase
=
true
,
array
$templateArray
=
[
UserTypeBasedCommandAccessRule
::
class
=>
[]
]
):
array
{
$base
=
[];
if
(
$includeBase
)
$base
=
array_merge
(
UploaderAccessControlPolicies
::
queriesPolicy
(),
UsersAccessControlPolicies
::
queriesPolicy
(),
GeneralAccessControlPolicies
::
queriesPolicy
(),
LangAccessControlPolicies
::
queriesPolicy
()
);
return
array_merge
(
$templateArray
,
$base
,
$policies
);
}
/**
* @param array $policies [(string|UserType::class)target => [ICommand:class]]
* @param bool $includeBase If true, will include default's WFW policies
* @param array $templateArray Template array to specify the command policies order
* @return array
*/
public
static
function
commandsPolicy
(
array
$policies
=
[],
bool
$includeBase
=
true
,
array
$templateArray
=
[
UserTypeBasedCommandAccessRule
::
class
=>
[]
]
):
array
{
$base
=
[];
if
(
$includeBase
)
$base
=
array_merge
(
UploaderAccessControlPolicies
::
commandsPolicy
(),
UsersAccessControlPolicies
::
commandsPolicy
(),
GeneralAccessControlPolicies
::
commandsPolicy
(),
LangAccessControlPolicies
::
commandsPolicy
()
);
return
array_merge
(
$templateArray
,
$base
,
$policies
);
}
/**
* @param array $policies [AccessRuleClass=>params]
* @param bool $includeBase If true, will include default's WFW policies.
...
...
@@ -34,6 +82,7 @@ final class WFWDefaultSecurityPolicy extends SecurityPolicy {
UploaderAccessControlPolicies
::
accessPolicy
(),
UsersAccessControlPolicies
::
accessPolicy
(),
GeneralAccessControlPolicies
::
accessPolicy
(),
LangAccessControlPolicies
::
accessPolicy
(),
[
ValidToken
::
class
=>
[]
]
);
return
array_merge
(
$templateArray
,
$base
,
$policies
);
...
...
@@ -54,8 +103,10 @@ final class WFWDefaultSecurityPolicy extends SecurityPolicy {
):
array
{
$base
=
[];
if
(
$includeBase
)
$base
=
array_merge
(
UploaderAccessControlPolicies
::
hooksPolicy
(),
UsersAccessControlPolicies
::
hooksPolicy
(),
GeneralAccessControlPolicies
::
hooksPolicy
()
GeneralAccessControlPolicies
::
hooksPolicy
(),
LangAccessControlPolicies
::
hooksPolicy
()
);
return
array_merge
(
$template
,
$base
,
$policies
);
}
...
...
engine/package/lang/security/LangAccessControlPolicies.php
View file @
e976758f
...
...
@@ -2,9 +2,11 @@
namespace
wfw\engine\package\lang\security
;
use
wfw\engine\core\security\SecurityPolicy
;
/**
* Lang package access control policies
*/
final
class
LangAccessControlPolicies
{
final
class
LangAccessControlPolicies
extends
SecurityPolicy
{
public
const
DISABLE
=
[
"^lang(/.*|)"
];
}
\ No newline at end of file
engine/package/uploader/security/UploaderAccessControlPolicies.php
View file @
e976758f
...
...
@@ -2,6 +2,7 @@
namespace
wfw\engine\package\uploader\security
;
use
wfw\engine\core\command\security\rules\UserTypeBasedCommandAccessRule
;
use
wfw\engine\core\security\rules\RequireAuthentification
;
use
wfw\engine\core\security\SecurityPolicy
;
...
...
@@ -11,6 +12,15 @@ use wfw\engine\core\security\SecurityPolicy;
class
UploaderAccessControlPolicies
extends
SecurityPolicy
{
public
const
DISABLE
=
[
"^uploader(/.*|)$"
];
/**
* @return array
*/
public
static
function
commandsPolicy
():
array
{
return
[
UserTypeBasedCommandAccessRule
::
class
=>
[]
];
}
/**
* @return array [AccessRuleClass => params]
*/
...
...
engine/package/users/security/UsersAccessControlPolicies.php
View file @
e976758f
...
...
@@ -3,8 +3,17 @@
namespace
wfw\engine\package\users\security
;
use
wfw\engine\core\action\NotFoundHook
;
use
wfw\engine\core\command\security\rules\UserTypeBasedCommandAccessRule
;
use
wfw\engine\core\security\rules\RequireAuthentification
;
use
wfw\engine\core\security\SecurityPolicy
;
use
wfw\engine\package\users\command\CancelPasswordRetrieving
;
use
wfw\engine\package\users\command\ChangePassword
;
use
wfw\engine\package\users\command\ChangeUserMail
;
use
wfw\engine\package\users\command\ConfirmUserMailChange
;
use
wfw\engine\package\users\command\ConfirmUserRegistration
;
use
wfw\engine\package\users\command\RegisterUser
;
use
wfw\engine\package\users\command\ResetPassword
;
use
wfw\engine\package\users\command\RetrievePassword
;
/**
* Users package control access policies
...
...
@@ -33,6 +42,27 @@ class UsersAccessControlPolicies extends SecurityPolicy{
];
}
/**
* @return array
*/
public
static
function
commandsPolicy
():
array
{
return
[
UserTypeBasedCommandAccessRule
::
class
=>
[
UserTypeBasedCommandAccessRule
::
PUBLIC
=>
[
RegisterUser
::
class
,
ResetPassword
::
class
,
RetrievePassword
::
class
,
ConfirmUserRegistration
::
class
],
UserTypeBasedCommandAccessRule
::
ANY
=>
[
ChangeUserMail
::
class
,
ConfirmUserMailChange
::
class
,
ChangePassword
::
class
]
]
];
}
/**
* @param bool $restrictMode
* @return array [HookClass => params ]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment