-
Notifications
You must be signed in to change notification settings - Fork 9
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
add validate api for totp #38
Conversation
f40c08c
to
fa71cd8
Compare
Hey @karakayasemi, We patched this commit to a 10.0.4EE ("version":"10.0.4.4","versionstring":"10.0.4","edition":"Enterprise"). I was able to query your API succesfully then:
That's exactly the functionality I was hoping to get, thanks. |
@Touchwoody I am glad that the expectations are met. @DeepDiver1975 I do not have much experience in API development. Your code review would be nice in here. Thanks. |
Hi Guys, Is there a plan when is this going to be this part released? |
@cdamken it is waiting for a review, I have not any idea about the release schedule |
@DeepDiver1975 Can you please review it? @patrickjahns Once is reviewed, could @owncloud/qa check if we can have some test? |
Tests should be easy enough, we can access whatever API the web UI does to enable TOTP for a user, and remember their secret key. Then there seem to be plenty of implementations of the TOTP key generator out there. So we can generate a current key and use it to make expected good queries. Excepted bad queries will be easy! |
🚫
|
I don't think the "secret" here is the "full secret private key" that was generated initially for the user. It is the 6-digit code that changes every 30 seconds or so. That "secret" is old and unusable 30 seconds later, so it is not so critical to keep it secret. The code here is not updating anything, it is just getting a confirmation if the 6-digit code is a currently-valid code. I am just clarifying a bit of what I see the code doing. @jvillafanez points above are still valid. |
Fair enough. However, I'd use "one-time-code" or "timed-code" or something similar instead of "secret" to prevent confusions. Just this rename feels a bit "safer" to send such code over the URL, but still I'd prefer to avoid it.
If only one line of the function is dedicated to validation and 3 lines to update the dbSecret.... you can rename the function to |
To clarify, what I requested for was an API call that tests, if an OneTimePassword is correct or not. No updates, just verify. For me, the call does exactly just that. This is a similar behavior as in the common LinOTP Service, see e.g.: I agree on putting more explanatory strings in the URL like "validate" or similar, will help to denote what the API call does. Come to think of it: I don't know if this is inherent in the API code base, but you need some brute force protection. Else I could send thousands of queries per second, might get a lucky hit and then know the current OTP for a few seconds. |
I just track old convention in the code by using "secret" keyword. Also, in the RFC of the TOTP protocol "shared secret key" is being used, because of that, I can not say wrong to use "secret" keyword in here.
I refactored verifySecret function of the Totp class by adding a try-catch block to catch an unhandled exception. But nothing changed in logic. As far as I understand, that was also confusing in the PR. We can move this to a separate commit. |
The app has unit tests - anything else can be added to the backlog and will need to be prioritized + scheduled accordingly |
aaef3f2
to
fbf11d2
Compare
Codecov Report
@@ Coverage Diff @@
## master #38 +/- ##
============================================
+ Coverage 62.6% 62.94% +0.33%
- Complexity 57 60 +3
============================================
Files 12 13 +1
Lines 230 251 +21
============================================
+ Hits 144 158 +14
- Misses 86 93 +7
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #38 +/- ##
============================================
+ Coverage 62.6% 64.68% +2.07%
- Complexity 57 61 +4
============================================
Files 12 13 +1
Lines 230 252 +22
============================================
+ Hits 144 163 +19
- Misses 86 89 +3
Continue to review full report at Codecov.
|
I converted API to OCS API and removed refactoring part of the commit. @jvillafanez I am not so experienced on this topic. Please help me with your code review. @Touchwoody also you can help me by testing the functionality. Thanks. |
lib/Controller/TotpApiController.php
Outdated
* @param string $secret | ||
* @return Result | ||
*/ | ||
public function validate($id, $secret) { |
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.
Try to use more meaningful names. Is the "id" as user id? a token id? a security id?
In addition, as said, "secret" is a bad name here since this is "linked" to the route.
Adjust the PHPDoc accordingly.
lib/Controller/TotpApiController.php
Outdated
*/ | ||
public function validate($id, $secret) { | ||
$user = $this->userManager->get($id); | ||
if (!empty($user)) { |
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.
The userManager returns either a IUser
object or null. Check for null or include a comment in the code explaining why empty
is a better choice.
lib/Controller/TotpApiController.php
Outdated
} catch (NoTotpSecretFoundException $e) { | ||
} | ||
} | ||
return new Result(['result' => false]); |
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.
Try to use DataResponse
since this class is public. Also verify the HTTP codes make sense
@@ -104,6 +104,8 @@ public function verifySecret(IUser $user, $key) { | |||
/** | |||
* @param IUser $user | |||
* @param string $key | |||
* @return boolean |
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.
Docs on the interface must be updated too. If there is an interface available I only care about what the interface says, if the implementation does any other thing outside interface, the implementation is buggy. If the interface doesn't say it can throw an exception, the implementation is the one to be blamed about bugs caused by it throwing exceptions. So, as said, update the interface too.
In addition, specially in the interface, explain the parameters. I don't want to check in every implementation what the "key" does (is it the secret to be validated?, a known id to fetch the secret from another place?, can I use any random string and expect it to work?) or why do I need to check for a "NoToptSecretFoundException" to be thrown. It must be known to whoever implements the interface under what conditions that exception is expected to be thrown.
I'm not saying to change anything in the code, I'm just suggesting to document the code better.
appinfo/routes.php
Outdated
'url' => '/api/v1/validate/{id}/{secret}', | ||
'verb' => 'GET', | ||
'requirements' => [ | ||
'id' => '.+', |
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'll need an explanation for these requirements.
For an url such as /api/v1/validate/userId/verySecret
I expect "id => userId" and "secret => verySecret". I expect that "/" is used as separator. The only way I think this could go wrong is if either the id or the secret contains a "/".
If the secret contains a "/" such as in /api/v1/validate/userId/very/top/Secret
I expect "id => userId" and "secret => very/top/Secret", which might be fair (I don't know what chars are used as secret, but having "/" as part of the set doesn't seem a good idea). However, the system could also assume "id => userId/very/top" and "secret => Secret" for the same url.
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.
You are right about the secret keyword, I will update code to use key
keyword instead of secret
and use uid
instead of id
.
However, Totp key is 6 digit number, cannot contain "/", also only the following characters are allowed in a username: "a-z", "A-Z", "0-9", and "_.@-'
. So, it can not contain "/" too. IMHO, there is no risk in url.
if (!empty($user)) { | ||
try { | ||
return new Result(['result' => $this->totp->validateSecret($user, $secret)]); | ||
} catch (NoTotpSecretFoundException $e) { |
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 expect this to be a rare occurrence, so at least we should log the exception.
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.
Actually, not every user have a totp secret. We are not enforcing 2-Factor Totp usage. So, the frequency changes depending on the usage of the API. But, we can log the exception.
3b8bf94
to
f65d624
Compare
07b37bb
to
c312afc
Compare
@jvillafanez I believe, I addressed all your requests. Please review one more time. Thanks. |
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.
Just double-check that inserting a "/" in either the userid or the key is safe.
@jvillafanez I tried to insert "/" to userid with both occ command and user management interface. It is not possible. Totp key is also can consist of only numbers. I believe it will not be a problem. @PVince81 It is ready to merge. I guess we should document this with the release. |
@karakayasemi please raise documentation tickets as needed and provide some content to explain what to document |
add OCS API for TOTP validation. Implementation of #29. @Touchwoody please test.
Open tasks before release
Usage
URL
/ocs/v1.php/apps/twofactor_totp/api/v1/validate/:user_id/:key?format=json
**Example test query for curl **
curl -u admin:pass 'http://base_url/ocs/v1.php/apps/twofactor_totp/api/v1/validate/{user_id}/{key}?format=json'
Method:
GET
URL Params
Required:
user_id=[string]
key=[string]