-
Notifications
You must be signed in to change notification settings - Fork 993
feat: implement callback authorisation for cli tokens #9502
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
Conversation
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA |
For reference, this is very similar to discord's handoff process (opens up a web browser when your desktop client is logged out).
For this, I use the clipboard history (Win+V on Windows), but I do think this is a valid concern.
Please do not return raw javascript code to be evaluated by the web page, this should be avoided at all costs and will probably not be allowed by the Content Security Policy anyways. Regarding security concerns, I'm not too fond of this.
You could also inject an extension into the browser, but that requires user consent. I think this would make it easier for a theoretical attacker to implement an auth stealer. |
Also, please run |
I don't think this is correct. Right now, the cli key can just be read straight out of the DOM, the attack vector is exactly the same. The only case where there is an additional attack vector is if the callback URL provided is malicious, however this can easily be avoided with validation on the URL and the user not randomly clicking auth links from unknown sources. |
Which would require an extension to be forced into the browsers, all major browsers prevent this behavior and need the user to accept the activation of the extension.
What kind of validation are you talking about exactly ?
Relying on the end user for security is a pretty poor practice in my opinion, I think we should always assume that the end user will do all kinds of bad things, but I also think this type of flaw can be avoided by design. I think I might come off as aggressive, that's not what I want, I just want to let you know that I'm reviewing every possibility. |
Can you propose an attack that only the proposed method is vulnerable to? |
Yes, the use of that login mechanism by an unauthorized client on the user's machine, which introduces less complexity when it comes to the attack mechanism. But now that I think about it, it's fine if you make the user accept on the page, the issue applies more to discord where this process is practically unattended. So therefore, not that big of a deal. I think a good way to mitigate the callback URL issue might be to do it like npm does. The advantage is also that you don't need to listen to a port on the local machine. npm does something like this:
I think this can be applied with websockets to be more efficient. What do you think? |
FWIW using the localhost listener for the browser callback is the RFC-8252 standard way to do this sort of thing for OAuth2 clients. That RFC specifically applies to a client trying to get an Oauth2 (or OIDC) access token, but it really applies just as well to any context where you're bridging a browser login to a native client (like a CLI). When used with a PKCE challenge in the flow, it does address most of the plausibly addressable security considerations. But the security considerations section of has pretty good coverage of things to consider if you want to make sure your bases are covered. |
Great UX improvement! I think we should always prompt stdin for the token because the An idea to consider that would work with remote terminals: sequenceDiagram
participant b as Authenticated Browser
participant c as CLI
participant s as coder server
c->>s: Open websocket at `/api/cli-login`
s->>c: Return login session ID
c->>b: Open /cli-login?id=${session_id}
b->>s: Authenticate ${session_id}
s->>c: Return authenticated session token
|
@ammario great idea! However I do think a websocket is overkill for this design. How the AWS CLI solves this is it just polls an endpoint every second or so to see if the session has been authenticated. The eventual workflow will look like this. sequenceDiagram
participant b as Authenticated Browser
participant c as CLI
participant s as coder server
c->>s: Request session ID: POST /api/sessions
s->>c: Return login session ID
Note over s,c: Display /cli-login?id=${session_id} in CLI in case browser cannot be opened.
c->>b: Open /cli-login?id=${session_id}
par CLI polls Server
loop Every n seconds
c->>s: GET /api/sessions/${session_id}.
alt not authenticated
s->>c: {"authenticated": false}
else is authenticated
s->>c: {"token": "nevergonnagiveyouup"}
end
end
and Browser authenticates with Server
b->>s: Authenticate ${session_id}
end
What do you think? |
|
This is a relatively in-progress implementation of a callback based token system for cli-auth.
Right now, we are finding it rather cumbersome to have to copy and paste the token into the CLI as we often already have something in the clipboard we want to keep.
I have implemented functionality that completes this token passing through HTTP. It works as follows:
127.0.0.1
). This is because we are able to assume that127.0.0.1
is safe and not susceptible to MITM attacks wherelocalhost
is.http.ListenAndServe
session in a goroutine so that the main thread is not blocked.authURL
and the user's browser is opened./cli-auth
is loaded, a check has been added to see if acallback
query param has been supplied, if so a single button interface requiring the user to press to authorize the callback is shown. I have included demonstrative callback_url validation in this page, we should be able to change this however is required.http://127.0.0.1:42069/auth?token=nevergonnagiveyouup
client.SetSessionToken
as per the original implementation.Todo
Security Concerns
In terms of security, I do not think this implementation is any less secure than what is used now. For the key to be leaked to an MITM attacker, they would either need scripted mouse control or be able to read the source of the returned page. Both of these attack vectors work on the existing implementation anyway, so the attack surface area there is no different. This would be different if the authorisation page automatically redirected to the callback URI but that is not the case.
Another attack vector could be a bogus callback url being replaced in the browser at some point. However I believe if this is able to happen, the user's machine is compromised anyway.
Also I have not been able to end-to-end test this as I cannot get the dogfood container to work- so any assistance there would also be eggsellent