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

Basic EXTJWT support #948

Closed
wants to merge 5 commits into from
Closed

Basic EXTJWT support #948

wants to merge 5 commits into from

Conversation

DanielOaks
Copy link
Member

@DanielOaks DanielOaks commented Apr 15, 2020

Spec is laid out over here (the whole URL verification thing is probably getting removed so don't worry about that at all). We currently don't store the time when users join the channel so the joined claim is just faked. For some reason my Go also removed github.com/goshuirc/e-nfa from the go.mod but not sure if that's okay because it's marked as indirect? ¯\_(ツ)_/¯

Either way this does the basics, let us know if you find anything wrong with this in the meantime.

Todos

  • Send correct user-joined-the-channel time.
  • Configurable token timeouts for services.

@DanielOaks
Copy link
Member Author

Yeah any help on the mod side would be appreciated, I'm not quite sure what's going on there but I get the feeling that latest commit didn't help aha.

@DanielOaks DanielOaks force-pushed the basic-extjwt-support branch from e84695d to 102e260 Compare April 16, 2020 07:54
@DanielOaks
Copy link
Member Author

note to self: updating go to the latest version is useful sometimes. cool in that case I think this does everything I want it to, happy for review~

Copy link
Member

@slingamn slingamn left a comment

Choose a reason for hiding this comment

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

Just getting some preliminary comments down --- feel free to ignore this until later, I want to hear back from the spec authors about why we need to track channel join times first.

@@ -35,6 +35,7 @@ type Channel struct {
key string
members MemberSet
membersCache []*Client // allow iteration over channel members without holding the lock
memberJoinTimes map[*Client]time.Time
Copy link
Member

Choose a reason for hiding this comment

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

Ugh --- there must be some reason this is necessary, but I can't figure out what it is yet. I asked a question about this on the spec PR. It would nice if we didn't need this.

Copy link
Member

@slingamn slingamn Apr 17, 2020

Choose a reason for hiding this comment

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

I discussed this with prawn and it sounds like we can just send 1 as the join timestamp (indicating "the client is joined, but the join timestamp is unavailable"); we can probably wait a couple days and then remove this tracking.

Copy link
Member Author

Choose a reason for hiding this comment

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

Once the spec is updated we can handle this however I guess, no worries

Copy link
Member

Choose a reason for hiding this comment

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

The spec got updated to allow 1 here.

irc/channel.go Outdated Show resolved Hide resolved
irc/config.go Show resolved Hide resolved
irc/channel.go Outdated Show resolved Hide resolved
irc/modes/modes.go Outdated Show resolved Hide resolved
irc/channel.go Outdated Show resolved Hide resolved
}
}

// we default to a secret of `*`. if you want a real secret setup a service in the config~
Copy link
Member

Choose a reason for hiding this comment

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

What's going on here exactly?

Copy link
Member Author

@DanielOaks DanielOaks Apr 17, 2020

Choose a reason for hiding this comment

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

If you provide a service name (like jitsi-call or acme-image-hosting) then it'll use the secret defined in that service's config block. By default it just uses a secret of * because there's really no reason to have a default secret that's customised (anything custom will just use a service name anyways).

Copy link
Member

Choose a reason for hiding this comment

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

Are we sure signing with a secret of * is correct? I found people saying that if there is no secret one should simply omit the signature: https://riptutorial.com/jwt/example/18558/unsigned-jwt

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, we should not be mixing and matching with alg: none because of the very frequent issues that alg:none has caused in the past. I'm not sure whether using * in particular is correct, but if the spec recommends using none rather than hmac then it is a horrendous decision honestly.

Copy link
Member

@slingamn slingamn Apr 19, 2020

Choose a reason for hiding this comment

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

I'm not 100% clear on what's going on here but I have a really strong intuition that using a secret key of * is incorrect.

If I'm reading the spec correctly, we should be requiring the operator to specify a default key of some kind (which should be a genuine secret and not *), and if they don't we should disable JWT (the command and the ISUPPORT token).

Should we ask for clarification on the spec PR?

Copy link
Member Author

@DanielOaks DanielOaks Apr 19, 2020

Choose a reason for hiding this comment

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

The spec should clarify this, yeah. There should not be any way to have a custom default secret, any custom secret should be provided by using a service name. So we should probably remove this and only advertise JWT if there is at least one service configured.

Copy link
Member

Choose a reason for hiding this comment

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

We got the clarification we wanted:

  1. The JWT header contains the signature algorithm, and the EXTJWT spec allows the use of any signature algorithm that can be verified. So I think what we have is fine. In the future, we could add, e.g., RSAPrivateKey to the JWTServiceConfig, and then the EXTJWT handler could sign with RSA instead if that field is populated.
  2. We should in fact have a default secret (and EXTJWT should be disabled if one is not specified).

Copy link
Member Author

@DanielOaks DanielOaks Apr 19, 2020

Choose a reason for hiding this comment

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

  1. So long as we never sign anything using the None algorithm, cool. Yeah could definitely add that key entry to the config in future no worries.
  2. But that... doesn't answer our question. Should the default be static (same on all nets, same everywhere, specified in the specification, etc) or should the default be decided by the network and it's totally OK if clients can't actually verify it? Prawn's response indicates that this is intended for use by clients that don't actually know anything about the ircd setup as well so would having a configurable default actually make sense there or would it e.g. screw up clients trying to just decode data (for example do any client libraries out there intentionally not decode stuff if the user doesn't have the correct verification key?)

Copy link
Member

Choose a reason for hiding this comment

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

should the default be decided by the network and it's totally OK if clients can't actually verify it

I'm very confident that this is the correct answer. Clients do not parse/validate the JWT token themselves, they hand it off to a third party. That third party is assumed to hold the correct verification key. (The original use case for this is a closed ecosystem of an ircd and a Jitsi, controlled by the same operator.)

A "secret key" that is a constant value written into a specification just doesn't make sense.

if err == nil {
maxTokenLength := 400

for maxTokenLength < len(tokenString) {
Copy link
Member

Choose a reason for hiding this comment

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

very elegant, i like this

@slingamn slingamn added this to the v2.1 milestone Apr 20, 2020
@slingamn slingamn modified the milestones: v2.1, v2.2 May 24, 2020
@slingamn slingamn mentioned this pull request Jun 15, 2020
@slingamn
Copy link
Member

I rebased this and it is now #1136.

@slingamn slingamn closed this Jun 15, 2020
@slingamn slingamn deleted the basic-extjwt-support branch July 20, 2020 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants