-
-
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
Signed requests #45979
Signed requests #45979
Conversation
58d3efd
to
f45a2cb
Compare
// remote does not support signed request. | ||
// currently we still accept unsigned request until lazy appconfig | ||
// core.enforce_signed_ocm_request is set to true (default: false) | ||
if ($this->appConfig->getValueBool('enforce_signed_ocm_request', false, lazy: true)) { |
Check failure
Code scanning / Psalm
InvalidArgument
if ($signatory === null) { | ||
throw new SignatoryNotFoundException('empty result from getRemoteSignatory'); | ||
} | ||
if ($signatory->getKeyId() !== $signedRequest->getKeyId()) { |
Check failure
Code scanning / Psalm
UndefinedInterfaceMethod
f45a2cb
to
a3dda22
Compare
61cc09b
to
9ef90c0
Compare
* @inheritDoc | ||
* | ||
* @param string $publicKey | ||
* @return IKeyPair |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* @inheritDoc | ||
* | ||
* @param string $privateKey | ||
* @return IKeyPair |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* @inheritDoc | ||
* | ||
* @param array $options | ||
* @return IKeyPair |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* @inheritDoc | ||
* | ||
* @param string $host | ||
* @return IOutgoingSignedRequest |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* @param string $key | ||
* @param string|int|float|bool|array $value | ||
* | ||
* @return IOutgoingSignedRequest |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* | ||
* @param string $estimated | ||
* | ||
* @return IOutgoingSignedRequest |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* | ||
* @param string $algorithm | ||
* | ||
* @return IOutgoingSignedRequest |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
* @inheritDoc | ||
* | ||
* @param array $signatureHeader | ||
* @return ISignedRequest |
Check failure
Code scanning / Psalm
MismatchingDocblockReturnType
/** | ||
* @inheritDoc | ||
* | ||
* @return ISignatory |
Check failure
Code scanning / Psalm
InvalidNullableReturnType
* @since 30.0.0 | ||
*/ | ||
public function getSignatory(): ISignatory { | ||
return $this->signatory; |
Check failure
Code scanning / Psalm
NullableReturnStatement
// if request is signed and well signed, no exception are thrown | ||
// if request is not signed and host is known for not supporting signed request, no exception are thrown | ||
$signedRequest = $this->getSignedRequest(); | ||
$this->confirmShareOrigin($signedRequest, $notification['sharedSecret'] ?? ''); |
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.
sharedSecret
inside the notification is already used by some OCM messages. So this would break it. Can you take another key? Or maybe you prefix with '$#$'
or something alike?
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.
this would not break it as I send the exception for the exact same reason of a missing 'sharedSecret' entry in the notifications request. The only thing is that I do this check earlier than others but I can add a prefix if you want (while I dont feel like necessary myself)
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.
this would not break it as I send the exception for the exact same reason of a missing 'sharedSecret' entry in the notifications request.
Nextcloud Talk is sending a data field 'sharedSecret'
and you either overwrite that and it breaks Talk Federation with older servers or you need to use a different key
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.
As said before, I only use this entry because it exists in the OCM protocol and doing so to compare that the origin of the reshare request, based on the token (and the linked recipient stored in the database), confirm the identity used to sign the request.
If Talk is using this endpoint to initiate anything, signature are to be required
apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
Outdated
Show resolved
Hide resolved
444f9e7
to
f3a1684
Compare
8807d38
to
5ac1e9a
Compare
952b97b
to
58e8195
Compare
58e8195
to
55a2663
Compare
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
55a2663
to
15b7228
Compare
]); | ||
$table->addColumn('metadata', Types::TEXT, [ | ||
'notnull' => true, | ||
'default' => '[]' |
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.
mysql> DESCRIBE oc_sec_signatory;
+--------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| key_id_sum | varchar(127) | NO | MUL | NULL | |
| key_id | varchar(512) | NO | | NULL | |
| host | varchar(512) | NO | | NULL | |
| provider_id | varchar(31) | NO | MUL | NULL | |
| account | varchar(127) | YES | | | |
| public_key | longtext | NO | | NULL | |
| metadata | longtext | NO | | NULL | |
| type | smallint | NO | | 9 | |
| status | smallint | NO | | 0 | |
| creation | int unsigned | YES | | 0 | |
| last_updated | int unsigned | YES | | 0 | |
+--------------+-----------------+------+-----+---------+----------------+
12 rows in set (0,00 sec)
Seems this does not work. TEXT fields can not have a default.
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.
This breaks Talk integration tests on:
MySQL
{"Exception":"OC\\DB\\Exceptions\\DbalException","Message":"An exception occurred while executing a query: SQLSTATE[HY000]: General error: 1364 Field 'metadata' doesn't have a default value"
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 think there is another failure with oracle catched by richdocuments integration tests:
{"Exception":"Exception","Message":"Cannot assign null to property NCU\\Security\\Signature\\Model\\Signatory::$account of type string in file '\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/Entity.php' line 149","Code":0,"Trace":[{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/AppFramework\/App.php","line":161,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Route\/Router.php","line":306,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/base.php","line":1019,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/index.php","line":24,"function":"handleRequest","class":"OC","type":"::"}],"File":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/AppFramework\/Http\/Dispatcher.php","Line":146,"Previous":{"Exception":"TypeError","Message":"Cannot assign null to property NCU\\Security\\Signature\\Model\\Signatory::$account of type string","Code":0,"Trace":[{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/Entity.php","line":59,"function":"setter","class":"OCP\\AppFramework\\Db\\Entity","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/QBMapper.php","line":315,"function":"fromRow","class":"OCP\\AppFramework\\Db\\Entity","type":"::"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/QBMapper.php","line":375,"function":"mapRowToEntity","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Security\/Signature\/Db\/SignatoryMapper.php","line":56,"function":"findEntity","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Security\/Signature\/SignatureManager.php","line":326,"function":"getByKeyId","class":"OC\\Security\\Signature\\Db\\SignatoryMapper","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Security\/Signature\/SignatureManager.php","line":140,"function":"getStoredSignatory","class":"OC\\Security\\Signature\\SignatureManager","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Security\/Signature\/SignatureManager.php","line":108,"function":"confirmIncomingRequestSignature","class":"OC\\Security\\Signature\\SignatureManager","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/apps\/cloud_federation_api\/lib\/Controller\/RequestHandlerController.php","line":339,"function":"getIncomingSignedRequest","class":"OC\\Security\\Signature\\SignatureManager","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/apps\/cloud_federation_api\/lib\/Controller\/RequestHandlerController.php","line":104,"function":"getSignedRequest","class":"OCA\\CloudFederationAPI\\Controller\\RequestHandlerController","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/AppFramework\/Http\/Dispatcher.php","line":200,"function":"addShare","class":"OCA\\CloudFederationAPI\\Controller\\RequestHandlerController","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/AppFramework\/Http\/Dispatcher.php","line":114,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/AppFramework\/App.php","line":161,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/private\/Route\/Router.php","line":306,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/base.php","line":1019,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/index.php","line":24,"function":"handleRequest","class":"OC","type":"::"}],"File":"\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/Entity.php","Line":149},"message":"Cannot assign null to property NCU\\Security\\Signature\\Model\\Signatory::$account of type string in file '\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/Entity.php' line 149","exception":{},"CustomMessage":"Cannot assign null to property NCU\\Security\\Signature\\Model\\Signatory::$account of type string in file '\/home\/runner\/actions-runner\/_work\/richdocuments\/richdocuments\/lib\/public\/AppFramework\/Db\/Entity.php' line 149"}
Signed Request
Signing request allows to confirm the identity of the sender.
Signing request does not encrypt nor affect its payload.
Signing request only adds metadata to the headers of the request.
Signature
The concept is to add unique metadata and sign them using a private/public key pair.
The location of the public key used to verify the signature will confirm the origin of the request.
Signature does not affect the data of the request, it only adds headers to it:
listed in 'headers' and their value. Some elements (content-length date digest host) are mandatory
to ensure authenticity override protection.
(Those are the minimum required headers, some can be added via options during the process)
ISignatoryManager
Because each protocol have different ways to obtain the public key of a remote instance or entity, some part of the signing/verifying process is managed by a custom provider, one for each protocol.
getProviderId
should returns a unique stringgetOptions
can returns an array that can contains those entries:getLocalSignatory
should return the local signatory, including the full (public+private) key pair.getRemoteSignatory
should returns a remote signatory based on the requested data, must at least contains key id and public keyISignatureManager
ISignatureManager
is a service integrated to core that provide tools to set/get authenticity of/from outgoing/incoming requests.getIncomingSignedRequest
extract data from the incoming request and compare headers to confirm authenticity of remote instancegetOutgoingSignedRequest
prep signature to sign an outgoing request.signOutgoingRequestIClientPayload
is the one method to call to fully process of signing and fulfilling the payload for an outgoing request using IClientsearchSignatory
get a remote signatory from the database