-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(middleware): Migrate BruteForceProtection annotation to PHP Attribute and allow multiple #36928
feat(middleware): Migrate BruteForceProtection annotation to PHP Attribute and allow multiple #36928
Conversation
…ibute and allow multiple Signed-off-by: Joas Schilling <coding@schilljs.com>
Signed-off-by: Joas Schilling <coding@schilljs.com>
c26dc84
to
2b49861
Compare
Documentation update at nextcloud/documentation#9742 |
@@ -68,18 +68,55 @@ public function beforeController($controller, $methodName) { | |||
if ($this->reflector->hasAnnotation('BruteForceProtection')) { | |||
$action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action'); | |||
$this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), $action); | |||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to add hasAttribute
/ getAttributes
to ControllerMethodReflector
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
THought about that too. I'm still up for it as a follow up, to combine the logic our for UseSession and this one.
Just thought it's easier to first get this in and then do more rework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m always afraid the follow-up never comes in these cases :-)
We should try to make the new way as easy to use as the previous one if we want the code to get migrated at some point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m always afraid the follow-up never comes in these cases
I guess you have a point, at the same time there is the RateLimit annotation waiting for me as a task this and next month, so will come.
if ($response->isThrottled()) { | ||
if ($this->reflector->hasAnnotation('BruteForceProtection')) { | ||
$action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action'); | ||
$ip = $this->request->getRemoteAddress(); | ||
$this->throttler->sleepDelay($ip, $action); | ||
$this->throttler->registerAttempt($action, $ip, $response->getThrottleMetadata()); | ||
} else { | ||
$reflectionMethod = new ReflectionMethod($controller, $methodName); | ||
$attributes = $reflectionMethod->getAttributes(BruteForceProtection::class); | ||
|
||
if (!empty($attributes)) { | ||
$ip = $this->request->getRemoteAddress(); | ||
$metaData = $response->getThrottleMetadata(); | ||
|
||
foreach ($attributes as $attribute) { | ||
/** @var BruteForceProtection $protection */ | ||
$protection = $attribute->newInstance(); | ||
$action = $protection->getAction(); | ||
|
||
if (!isset($metaData['action']) || $metaData['action'] === $action) { | ||
$this->throttler->sleepDelay($ip, $action); | ||
$this->throttler->registerAttempt($action, $ip, $metaData); | ||
} | ||
} | ||
} else { | ||
$this->logger->debug('Response for ' . get_class($controller) . '::' . $methodName . ' got bruteforce throttled but has no annotation nor attribute defined.'); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is a good piece of code to refactor and split the responsibility at separated method to make the reading more easy.
Maybe anything like:
->parseBruteForceAnnotation
->parseBruteForceAttributes
Previously (and still supported)
New syntax
Multiple attributes now supported
By specifying an
'action'
in thethrottle($metadata)
only the dedicated attribute will trigger it's BFP, if none is specified all will throttle.This is useful e.g. in controllers that need to protect different data, e.g. Talk has the tokens and the signaling secret in the same method and needs to do a lot of manual work instead of just calling
throttle
on the response:https://github.com/nextcloud/spreed/blob/29a442cf86d49b426ecd47776c86ab6f6de5da58/lib/Controller/SignalingController.php#L154-L179
🚧 ToDo
Checklist