Skip to content
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

Fix inconsistencies in app key validations #3639

Merged
merged 8 commits into from Dec 4, 2023

Conversation

mayorova
Copy link
Contributor

@mayorova mayorova commented Nov 27, 2023

What this PR does / why we need it:

There is a number of issues with the current validation rules for User Keys, Application IDs and Application Keys:

  • what's stated in the UI in the hints is just not correct for App Ids and Keys
  • some characters that are accepted by System, can not be synchronized with Backend (for example, keys containing /) - so the user will think the key is correct, but it will never work for API auth.
  • some characters that are supposed to be accepted (specifically .) are actually rejected by System (because it's not accepted in Rails path by the router by default).
  • user_key field allows empty value, but this just doesn't work. Trying to open such an app when a service uses API Key auth method returns a 500 Internal Server Error. Also, obviously such a key can't be synchronized with backend, so is not functional.

Which issue(s) this PR fixes

https://issues.redhat.com/browse/THREESCALE-7570

https://issues.redhat.com/browse/THREESCALE-10002

Verification steps

  1. Try to set a user key, app ID or app key with a / or a space and confirm that the operation does not succeed, and the appropriate error is shown.

  2. Try to create and delete an application key with a dot . in it, and confirm that it works as expected.

  3. Try to update an application and set an empty user_key, it should fail.

Special notes for your reviewer:

The issue with slashes (failing on the backend) is due to path traversing protection in sinatra that apisonator uses.
In this PR we're just forbidding / in user keys, app IDs and keys.

But alternative (maybe a better) approach could be to fix it on apisonator side by setting the following for the internal API:

set :protection, except: :path_traversal

But I'm not 100% sure that it is safe and doesn't have any negative consequences, so I thought we could be more conservative and just disallow /. This character doesn't work at this moment anyway, so we're not removing any existing functionality. Also, it has never been documented anywhere that it was a supported character.

There might be an issue for some customers that might potentially use 3scale together with their 3rd party OpenID / OAuth providers that generate client ID and secrets automatically, and might include /. But if requested by anyone, we can revisit.

app/models/cinstance.rb Show resolved Hide resolved

validates :user_key, format: { with: /\A#{USER_KEY_FORMAT}\Z/ }, length: { maximum: 256 },
allow_nil: true, allow_blank: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How could a user key be nil before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still can be, because allow_blank includes nil as well...

I will check if there are such entries in the DB. In theory those applications that are on App Id / App Key or OpenID modes don't need user_key, but I think technically they would still be auto-generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I'm thinking... Maybe we need to stop allowing blank values, I think it doesn't make any sense. And actually, there are not so many blank user keys in the current DB, about 9 on the accounts that are still active, and among these there are at least 3 that belong to internal test accounts...

So, I think we can remove allow_blank as well.

# The following characters are accepted:
# A-Z a-z 0-9 ! " # $ % & ' ( ) * + , - . : ; < = > ? @ [ \ ] ^ _ ` { | } ~
# Spaces and / are not allowed
validates :application_id, format: { with: /\A[\x21-\x2E\x30-\x7E]+\Z/ }, length: { in: 4..255 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could prevent updating existing applications as well. I've been looking for any touch among Cininstance associations that could try to update the application as a result of some other action. The only thing I found is this:

proxy_association.owner.touch if succeeded

I'm not sure what that proxy_associtation.owner means, could it be the Cinsntance? If that's the case Oauth applications won't be able to regenerate keys on if they have spaces or slashes in their ids.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I'll check that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are just 2 apps with invalid app ID: one is on test account, and another one is not in use since 2020.

test/unit/application_keys_test.rb Outdated Show resolved Hide resolved
@jlledom
Copy link
Contributor

jlledom commented Nov 28, 2023

I tried locally and the UI works fine for me.

I found an issue when trying to send queries to apicast. These are the keys for my app:

image

Using the key abc.abc works fine:

$ curl "http://api-2.staging.apicast.dev:8080/?app_id=d0945643&app_key=abc.abc"
{
  "method": "GET",
  "path": "/",
  "args": "app_id=d0945643&app_key=abc.abc",
...

But I couldn't use the [abc] key:

$ curl "http://api-2.staging.apicast.dev:8080/?app_id=d0945643&app_key=%5Babc%5D"
Authentication failed

Am I doing something wrong?

Co-authored-by: Joan Lledó <jlledo@redhat.com>
@mayorova mayorova force-pushed the fix-inconsistencies-in-app-key-validations branch from 0061ffb to 4972ca5 Compare November 28, 2023 09:32
@mayorova mayorova marked this pull request as ready for review November 28, 2023 13:41
@mayorova
Copy link
Contributor Author

mayorova commented Nov 29, 2023

It's great that you have checked this @jlledom !

I've tried this also, and it turns out that when you encode in the curl command, backend receives the key kind of double-encoded (% is changed to %25): app_id=d0945643&app_key=%255Babc%255D

[] have a special meaning in curls, but they can be escaped:

$ curl "http://api-2.staging.apicast.dev:8080/?app_id=d0945643&app_key=\[abc\]"

or alternatively:

$ curl --globoff "http://api-2.staging.apicast.dev:8080/?app_id=d0945643&app_key=[abc]"

See "globbing letters" in https://curl.se/docs/url-syntax.html

Note that there is another outstanding issue that is not solved here: https://issues.redhat.com/browse/THREESCALE-9033
It will be solved separately, as it requires a change to pisoni gem.

Copy link
Contributor

@jlledom jlledom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If don't feel like doing the refactor that's fine.

Comment on lines +12 to 15
# TODO: Refactor and remove me
def backend_id
prefix_key
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance, it seems this could be replaced by alias :backend_id :id. I would prevent adding #TODOs amd #FIXMEs if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#3647

It would probably be more correct to have:

def backend_id
  id.to_s
end

because this would be a full equivalent of the current situation.

However, using an integer instead of string should not have a negative effect.

Comment on lines +262 to 265
# TODO: Refactor and remove me
def prefix_key(key = id)
key.to_s
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be just removed and prevent adding more #TODOs. You would need to make some changes in the places where this is called from. If after the changes it passes the tests, I'd say it's safe enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd prefer to do it in another PR, because some of the changes are unrelated. I promise to fix it ASAP! 😛

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you go: #3647

user_key: "Only alphanumeric characters [0-9, a-z, A-Z], hyphen-minus (-) and underscore, no spaces and up to 256 characters."
key: "Only alphanumeric characters [0-9, a-z, A-Z], hyphen-minus (-) and underscore, no spaces and between 5 and 255 characters."
user_key: "Allowed characters: [A-Z a-z 0-9 - _ .], or Base64 format without forward slash (/), no spaces and up to 256 characters."
key: "Allowed characters: [A-Z a-z 0-9 ! \" # $ % & ' ( ) * + , - . : ; < = > ? @ [ \ ] ^ _ ` { | } ~], no spaces and between 5 and 255 characters."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@josemigallas what do you think, are those messages OK?

@mayorova mayorova merged commit 6847767 into master Dec 4, 2023
17 of 21 checks passed
@mayorova mayorova deleted the fix-inconsistencies-in-app-key-validations branch December 4, 2023 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants