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
LDAP Authentication #346
base: master
Are you sure you want to change the base?
LDAP Authentication #346
Conversation
TODO: Make the styles match the rest of the page and move them out of inline.
thanks for the effort here 👍 it also may take some time for me to review since i don't know anything about LDAP. and i don't think i should blindy accept something i don't know about (no offense 😁) i will do some reading or get a second pair of eyeballs on it there seems to be some lint errors btw |
Actually, they wouldn't even have a subsonic password: you can dynamically create a subsonic user after a successful bind. "I didn't know about this user, but the LDAP server tells me they exist and have access to subsonic, so I'll create an account for them" Usually, the flow goes like:
When querying the LDAP server (usually as the admin to save one query), you can also fetch some more details from LDAP, such as the user's email and/or display name. |
thanks for the info 👍 also, and from gonic's perspective would it be standard practice to hit the LDAP for every http request is receives? seems like a lot of overhead, esp considering the case of browsing a list of albums from a browser. that could be 100s of request to gonic like getCoverArt.view?id=x&p=xxx, which is in turning hitting the LDAP server for each request |
No, logging a user in can be an expensive operation (think multiple rounds of cryptographic hashing if you want something secure). Repeated attempts to log in can fairly easily bring an authentication server to its knees if it's not protected. Usually you'd call the LDAP server once when logging in, then remember the login. Either through a session token, some JWT or similar, you'd get a short-to-medium term authorization (e.g. 1h, 24h, until 20min of inactivity, until explicit logout, etc). Note that the user's access to the server (gonic) can change at any time and you won't be notified of that; you'll only see that when they next try to log in. As a result, keeping the session until the user explicitly logs out is not recommended (but could be offered as an option for those who want it, along with a way to forcefully invalidate the user's active sessions). |
The best why I can think of doing this is syncing passwords from the LDAP server (ie. checking local accounts, querying the LDAP server if it fails, then create the user if it doesn't exist, update the password if it's out-of-date). This does have a few caveats (as for every failed login there would be a request to the LDAP server, which could be avoided with some sort of rate limit -- but that leads to out of date credentials). Other than this, I'm not sure if there is any amazing way of implementing this, as far as I know (standard) LDAP doesn't have any token exchange, nor does OpenSubsonic. |
Getting the password (hashes) from LDAP is not recommended, both in terms of security (you don't want to spread them everywhere and increase the attack surface) and compatibility (not every server hashes them in a compatible way). For instance, LLDAP doesn't expose the password hashes because it's doing a zero-knowledge proof that basically can't be replicated in gonic. How does normal auth work in gonic? The credentials are sent with every request? You can implement a server-side auth caching method, i.e. "these credentials were authorized by the LDAP server at time T, so they'll be valid until T+24h before we recheck them" |
I totally agree on the security thing, it was a concern I had with the idea too, but my thought was that you could just hash the password after the request (considering gonic would already know it). I still don't think it's a good idea though.
Yeah, every request includes URL parameters.
I was thinking about this, and the more I do the more logical it seems. I don't know how @sentriz would feel, but the password reset button (in the web UI) could be replaced with an "LDAP refresh" button for LDAP users/in LDAP mode to clear the cache for that user. |
@sentriz, on implementing a cache for LDAP credentials, currently local user passwords are stored in plain text - which I think we can all agree is not a safe long-term solution. Although, this raises the question as to how securing the cache should be approached, I can think of a few ways of doing this (but wanted to run them by you before doing anything that might not fit in with the project) including implementing:
Also, if you don't want to add hashing yourself to the database, I might be able to add it later (although I don't have the resources to work on opening another pull request at the moment). |
to my knowledge, storing is plaintext is a requirement from the subsonic protocol. this is to check credentials using the salt+token method |
there is some more discussion here opensubsonic/open-subsonic-api#25 |
Sorry for the late response, but I hadn't thought of that, thanks for letting me know. |
@nitnelave, this has been done in fccf016. |
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.
hi there seems like there some lint errors
@@ -106,7 +125,7 @@ func main() { | |||
log.Fatalf("invalid exclude pattern: %v\n", err) | |||
} | |||
|
|||
if len(confMusicPaths) == 0 { | |||
if len(confMusicPaths) == -1 { |
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.
is this left over from testing or smth?
Limitations
Fixes: #44.