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

feat(authentication): add LDAP authentication support #1093

Merged
merged 26 commits into from
Aug 10, 2017

Conversation

deviantony
Copy link
Member

This PR introduces a new Authentication section in the Settings of Portainer. It will allow you to choose between Internal (managed by Portainer) and LDAP authentication.

Close #677

@deviantony deviantony added docker-image-available work-in-progress Indicates that the PR is a work-in-progress and not ready yet labels Aug 5, 2017
@deviantony
Copy link
Member Author

You can test this feature using the image portainer/portainer:pr1093 (Linux amd64 build).

@deviantony deviantony removed the work-in-progress Indicates that the PR is a work-in-progress and not ready yet label Aug 6, 2017
@WTFKr0
Copy link
Contributor

WTFKr0 commented Aug 6, 2017

Will test that this week

@DimeOne
Copy link

DimeOne commented Aug 8, 2017

I started my preexisting portainer container with the image portainer/portainer:pr1093.

Within the user management, the password fields were missing and I could not see any options for ldap.

@ncresswell
Copy link
Member

ncresswell commented Aug 8, 2017 via email

@deviantony
Copy link
Member Author

Within the user management, the password fields were missing and I could not see any options for ldap.

When LDAP is enabled, Portainer will automatically hide password management. So that would mean that LDAP is already enabled on your instance.

@DimeOne
Copy link

DimeOne commented Aug 9, 2017

It seems I must have been blind (or too tired). I was looking at Settings but must have overlooked the Authentication Menuitem.

I was not able to get it working like I did with other applications. This is my home lab which is using a Microsoft Active Directory running on a Windows Server 2012R2. I have been able to configure the connection using other tools like Jenkins, All Certificates are issued by my own pki and are working fine. LDAP has been tested on 389+3268(plain+starttls), 636+3269(SSL) using LDAP Admin.

  1. Not able to login
    Even though the connection seems to work while testing it, I was not able to login to portainer using ldap. (Neither with plain nor TLS)
    If I create the user as administrator before logging in, I receive:
    "http error: User not found or too many entries returned (code=500)"
    Otherwise it says:
    "http error: Invalid credentials (code=400)"

This may be due to the missing User search configurations.

  1. incomplete TLS Settings
    I was trying to configure a tls connection on port 389 which uses starttls. I uploaded only the certificate chain and saved the settings, without being able to test the connection. ( Due to missing tls cert and key ?! ) Upon reloading the settings, all tls items are checked and the test connection button is active. Testing the connections returns an error, that the certificate cannot be found.

I assume that this tls is only used for client authentication?

2017-08-09_134348

  1. SSL Connection
    After failing to establish a starttls connection, I tested an SSL connection on port 636, which failed too.
    Error on failure was "Connection reset by peer"

Setting the protocol explicitly to ldaps:// within the LDAP URL is not supported either.

@deviantony
Copy link
Member Author

@DimeOne thanks for the feedback !

Not able to login
Even though the connection seems to work while testing it, I was not able to login to portainer using ldap. (Neither with plain nor TLS)
If I create the user as administrator before logging in, I receive:
"http error: User not found or too many entries returned (code=500)"
Otherwise it says:
"http error: Invalid credentials (code=400)"

There was an issue that was fixed this morning where the User search configurations would not appear when using previous Portainer data (you can pull again portainer/portainer:pr1093 to retrieve the fix).

There User not found or too many entries returned (code=500) error is raised when the LDAP search query returns either no or too many entries. Tho without search settings, it's highly probable that this would be raised.

incomplete TLS Settings
I was trying to configure a tls connection on port 389 which uses starttls. I uploaded only the certificate chain and saved the settings, without being able to test the connection. ( Due to missing tls cert and key ?! ) Upon reloading the settings, all tls items are checked and the test connection button is active. Testing the connections returns an error, that the certificate cannot be found.

SSL Connection
After failing to establish a starttls connection, I tested an SSL connection on port 636, which failed too.
Error on failure was "Connection reset by peer"

I was not able to test the TLS connection, indeed all 3 TLS fields are mandatory so I'm pretty sure it won't work without the TLS trio.

Setting the protocol explicitly to ldaps:// within the LDAP URL is not supported either.

You don't need to specify the protocol in the URL field.

You can ping me on Slack for a more reactive support / communication.

@DimeOne
Copy link

DimeOne commented Aug 9, 2017

After pulling the latest pr1093 I was able to get LDAP login to work (without tls/ssl).

For AD I used following user search configurations:
BaseDN: CN=Users,DC=example,DC=org
Username attribute: sAMAccountName
Filter: (objectClass=user)

I had to add the users manually, but then I was able to login with said users.

If you could give me a reference to the documentation of the library you used for ldap, I may take a look at encryption.

P.S.: Great product, keep on with the good work :) 👍

@deviantony
Copy link
Member Author

deviantony commented Aug 9, 2017

@DimeOne nice to hear that !

I used the following library for the implementation: https://github.com/go-ldap/ldap (godoc available at https://godoc.org/gopkg.in/ldap.v2)

I've specifically used https://godoc.org/gopkg.in/ldap.v2#DialTLS to establish a TLS connection, this is using a *tls.Config object (https://godoc.org/crypto/tls#Config).

See the createConnection method here: https://github.com/portainer/portainer/blob/feat677-ldap-support/api/ldap/ldap.go#L51 (the whole LDAP implementation is in that file)

The *tls.Config object is created via https://github.com/portainer/portainer/blob/feat677-ldap-support/api/crypto/tls.go#L10-L26

@DimeOne
Copy link

DimeOne commented Aug 9, 2017

Within the dokumentation is a StartTLS with a basic example that skips certificate verification, more secure options would include a certificate chain, servername within the config: https://godoc.org/crypto/tls#Config
func (l *Conn) StartTLS(config *tls.Config) error

err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
if err != nil {
log.Fatal(err)
}

The changes I would make:

  • Change "TLS" switch to "Use Encryption"
  • Add new Switch for "TLS vs StartTLS"
  • Add new Switch for "Skip Verification"
  • require Certificate Chain when no Skip Verification is specified and use in tls.Config.RootCAs
  • Set servername in tls.Config.Servername
  • Make Cert and ClientCert optional for Client Authentication - ( bind_dn and password would then be optional )

That should allow using ldap with encryption and validation with TLS and StartTLS. I'm not familiar with go and could provide a patch for that, but I'd be happy to give feedback and test it at home and work :)

@deviantony
Copy link
Member Author

@DimeOne

Sweet, let me make some changes and I'll ping you to give it a try :-)

@deviantony
Copy link
Member Author

@DimeOne would you be able to join me on Slack as I've got multiple questions ? https://portainer.io/slack/

@DimeOne
Copy link

DimeOne commented Aug 9, 2017

Never used slack before, I'll figure it out in a few minutes

@deviantony deviantony merged commit d27528a into develop Aug 10, 2017
@deviantony
Copy link
Member Author

Thanks everyone for your feedback on this !

@DimeOne Now that it's merged into develop, do you mind testing again the TLS settings ? (I did some cleanup and want to be sure I did not broke anything). You should be able to use portainer/portainer:develop.

@artisticcheese
Copy link

Does this work now with Windows containers?

@deviantony
Copy link
Member Author

@artisticcheese our instable build is not available as a Windows container yet (only linux amd64 build). Tho it will be released this week !

@beenanner
Copy link

I get the following after setup of ldap. Is there a limit of the # of users portainer can handle on it's side? I'll dig in a bit more when I have time.

{"err":"User not found or too many entries returned"}

@beenanner
Copy link

Everything seems to work if I restrict the results to just a single user via the filter option in the "User search configurations".

(uid=%s) <--- doesn't work
(uid=beenanner) <--- does work

@deviantony
Copy link
Member Author

deviantony commented Aug 13, 2017

@beenanner if you want to use (uid=%s) you can just set the value uid in the username attribute field. This is the attribute on which the username will be matched.

Is there a limit of the # of users portainer can handle on it's side?

No there is not.

{"err":"User not found or too many entries returned"}

This error is raised when the LDAP search query returned either 0 results or more than 1 (probably due to incorrect search settings).

@deviantony deviantony deleted the feat677-ldap-support branch August 13, 2017 18:18
@beenanner
Copy link

Nice @deviantony, I tried your suggestion and just removed the filter and everything is working! Awesome job and welcomed feature!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants