Single sign-on (SSO)/Identity and access management (IAM) for Nethserver

So as is often the case, one thing leads to another, which leads to another, and now I’m starting to look at SSO/IAM software. There appear to be a number of F/OSS solutions in this field, and it’s looking like it’s something that could improve system security quite a bit.

Right now, Neth uses LDAP (either a local OpenLDAP server, a remote one, or AD) for authentication. Applications take the username and password, validate them against the LDAP server, and grant access. It’s fairly simple, it’s widely supported, and it’s pretty easy to implement. But…

Every application that requires login is now at risk to compromise user credentials, because each of those applications handles those credentials. And if you want to implement 2FA, each application needs to support it, and you can only use the methods supported by that application.

By contrast, the SSO application handles authentication directly. When you click the Login button in Nextcloud, for example, you’re redirected to the SSO app, which authenticates you (including 2FA if desired), and then returns you to Nextcloud. Nextcloud never sees your password, so it can’t leak it. And if you want to use hardware authenticators like YubiKeys, Nextcloud doesn’t need to support FIDO2, U2F, or whatever. In addition, they typically support authentication mechanisms like SAML and OpenID Connect, allowing them to handle additional scenarios that LDAP won’t handle (the particular one I have in mind being using Step CA to issue SSH certificates).

So why aren’t we using them already? I expect there are a few major reasons:

  • Complexity of installation
  • Resource requirements
  • Complexity of configuration–both for the SSO software, and for the client app
  • Many web apps don’t support more involved authentication mechanisms like SAML or OIDC

I think the security benefit still makes them worth some investigation, and there are (as I said above) a few F/OSS options. I know of:

AFAIK, all of these can authenticate against the LDAP database Neth is already using (being able to add users to that database, as Martin had been asking for, seems less common), so user creation wouldn’t necessarily need to change, but we would need to investigate having all of our other web apps use one of these other authenticators.

  • Nextcloud is reported to have good support for SAML
  • So is SOGo
  • Other software would take some research

Here’s the start of a comparison table among the F/OSS products I know of. Feel free to suggest rows to add or corrections (unless a mod can make this a wiki post):

Gluu WSO2 IS Keycloak LemonLDAP::NG ORY Hydra
Client Authentication Technologies
OpenID Connect :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:
SAML :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:
CAS :white_check_mark: :white_check_mark:
HTTP Headers :white_check_mark:
Other
Written In Java Java Java Perl Go
License Apache 2.0 Apache 2.0 Apache 2.0 GPL2 Apache 2.0
Doctor Who? :white_check_mark:
6 Likes

Take a look also to https://www.ory.sh/hydra/

I’d like to have such feature for NS 8 :slight_smile:

Thanks, another one to add to the list. Edit: though it looks like most of its components aren’t considered stable at this point; only Hydra itself is:

It also looks like Hydra, at least, is only a backend system–it doesn’t provide any sort of UI (e.g., a login page). OTOH, it’s written in Go (many of the others use Java), seems much more lightweight, and appears to be easily deployable as a Docker container (which isn’t really the case for Gluu, at least). Looks like it might be time to put together a comparison table…

Looking over some of the docs, I see that LemonLDAP::NG has some pretty complete docs on client setup–for a number of popular apps (including Nextcloud and Roundcube), they detail how to set them up to authenticate to LemonLDAP::NG. That’s helpful, especially since Nextcloud has now put their docs behind a paywall.

Cockpit looks like it could be a problem though. The only mechanism I can see that’s supported is Kerberos, and it doesn’t look like many of these products support that.

1 Like

So I’ve been playing with LemonLDAP::NG a bit, and it’s looking nice, but right now I’m having trouble getting it to talk to a LDAP server on a Neth box. For now, I’m running LemonLDAP on a CentOS 7 VM, and Neth 7.9 on a separate VM. The Neth box is using local OpenLDAP as the accounts provider. Running ldapsearch from the CentOS machine seems to work:

[root@auth log]# ldapsearch -x -b dc=directory,dc=nh -H ldap://192.168.1.52
# extended LDIF
#
# LDAPv3
# base <dc=directory,dc=nh> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# directory.nh
dn: dc=directory,dc=nh
objectClass: top
objectClass: dcObject
objectClass: organization
dc: directory
o: Neth LemonLDAP Test

# People, directory.nh
dn: ou=People,dc=directory,dc=nh
objectClass: top
objectClass: organizationalUnit
ou: People

# Groups, directory.nh
dn: ou=Groups,dc=directory,dc=nh
objectClass: top
objectClass: organizationalUnit
ou: Groups

# libuser, directory.nh
dn: cn=libuser,dc=directory,dc=nh
objectClass: device
objectClass: simpleSecurityObject
cn: libuser
description: libuser management account

# ldapservice, directory.nh
dn: cn=ldapservice,dc=directory,dc=nh
objectClass: device
objectClass: simpleSecurityObject
cn: ldapservice
description: ldapservice management account

# locals, Groups, directory.nh
dn: cn=locals,ou=Groups,dc=directory,dc=nh
gidNumber: 1001
cn: locals
objectClass: posixGroup

# admin, People, directory.nh
dn: uid=admin,ou=People,dc=directory,dc=nh
uidNumber: 1001
gidNumber: 1001
uid: admin
shadowMax: 99999
shadowWarning: 7
shadowMin: 0
loginShell: /usr/libexec/openssh/sftp-server
homeDirectory: /var/lib/nethserver/home/admin
shadowInactive: -1
shadowExpire: -1
gecos: admin
shadowLastChange: 18673
shadowFlag: -1
cn: admin
sn: admin
objectClass: posixAccount
objectClass: shadowAccount
objectClass: inetOrgPerson
mail: admin@familybrown.org

# domain admins, Groups, directory.nh
dn: cn=domain admins,ou=Groups,dc=directory,dc=nh
gidNumber: 1002
objectClass: posixGroup
memberUid: admin
cn: domain admins

# fred, People, directory.nh
dn: uid=fred,ou=People,dc=directory,dc=nh
uidNumber: 1002
gidNumber: 1001
uid: fred
shadowMax: 99999
shadowWarning: 7
shadowMin: 0
loginShell: /usr/libexec/openssh/sftp-server
homeDirectory: /var/lib/nethserver/home/fred
shadowInactive: -1
shadowExpire: -1
gecos: Fred Flintstone
shadowLastChange: 18673
shadowFlag: -1
cn: Fred Flintstone
sn: fred
objectClass: posixAccount
objectClass: shadowAccount
objectClass: inetOrgPerson
mail: fred@familybrown.org

# search result
search: 2
result: 0 Success

# numResponses: 10
# numEntries: 9

But when I configure LemonLDAP to connect to that server as follows:

I get this error on the login screen:
image

…with this not-very-helpful message in Apache’s error_log:

[Sun Feb 28 14:45:49 2021] [LLNG:4062] [error] IO::Socket::INET: connect: Permission denied
[Sun Feb 28 14:45:49 2021] [LLNG:4062] [error] LDAP initialization error: IO::Socket::INET: connect: Permission denied
1 Like

SSO is something wanted in professional environment, indeed when you have different MFA, it is something awful when you want to authenticate after the LDAP of NS. However SSO is something that needs to be created, it is not free, each application must be configured.

@danb35

Hi Dan

Looks to me like a permissions issue.
IO and Sockets are normally off limits for the apache user - for obvious security reasons.
It depends on how secure the default settings are on that Centos box, but you may need to add the apache user to a group (or several)…
Try maybe “dialout” (needed for access to usb / serial, but maybe other things as well…

My 2 cents
Andy

Close, turned out it was a SELinux issue. setsebool -P httpd_can_network_connect 1 fixed that. Now getting authentication failures, but it’s a step farther.

This is true with LDAP as well, it’s just that the configuration for LDAP auth is quite a bit simpler. But, as you say, you can’t really do 2FA with LDAP.

2 Likes

A little confused here. I have Nextcloud installed on my test Neth server, and it’s set up (by default) to authenticate against the built-in OpenLDAP server. I’ve created a test user, and that user can sign in to that Nextcloud installation. But from the CentOS VM, I can’t authenticate as that user:

[dan@auth ~]$ ldapsearch -x -LLL -h 192.168.1.52 -D 'cn=fred,dc=directory,dc=nh' -W -b"dc=directory,dc=nh" -s sub "(objectClass=inetOrgPerson)" givenName
Enter LDAP Password: 
ldap_bind: Invalid credentials (49)

Everything I’m seeing indicates this should work, but LDAP is largely opaque to me. The -h parameter contains the IP address of the Neth box. When I run the same command on the Neth box, I get the same result. But when I instead specify -h localhost, I get ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1).

For Nethserver LDAP users you may need the People OU like

cn=fred,ou=People,dc=directory,dc=nh

I used this LDAP search recently (with ldapservice user) for starttls testing:

1 Like

Unfortunately, that also doesn’t work:

[root@neth-lemon ~]# ldapsearch -x -LLL -h 192.168.1.52 -D 'cn=fred,ou=People,dc=directory,dc=nh' -W -b"dc=directory,dc=nh" -s sub "(objectClass=inetOrgPerson)" givenName
Enter LDAP Password: 
ldap_bind: Invalid credentials (49)

It’s uid=fred instead of cn. The following should work:

ldapsearch -x -LLL -h 192.168.1.52 -D 'uid=fred,ou=People,dc=directory,dc=nh' -W -b"dc=directory,dc=nh" -s sub "(objectClass=inetOrgPerson)" givenName
[root@neth-lemon ~]# ldapsearch -x -LLL -h 192.168.1.52 -D 'uid=fred,ou=People,dc=directory,dc=nh' -W -b"dc=directory,dc=nh" -s sub "(objectClass=inetOrgPerson)" givenName
Enter LDAP Password: 
ldap_bind: Invalid credentials (49)

From remote you need the -Z option for starttls instead of the -x (simple auth).
I wonder that one gets a misleading “invalid credentials” error because of wrong encryption.

ldapsearch -Z -LLL -h 192.168.1.52 -D 'uid=fred,ou=People,dc=directory,dc=nh' -W -b"dc=directory,dc=nh" -s sub "(objectClass=inetOrgPerson)" givenName
1 Like

The example I posted wasn’t from a remote host, but from the Neth host–but apparently when I connect using its IP address, it still treats it as a remote connection. If I change the command to -h localhost (keeping the -x flag in the command), that works. From the remote host, if I change -x to -Z, it works. Cool.

And more to the point, now that I know that works, once I change the connection to ldap+tls://hostname, LemonLDAP is able to authenticate against the Neth LDAP system.

Edit: I’m realizing that I made my job quite a bit harder than it needs to be by putting LemonLDAP on a separate CentOS 7 VM, rather than just running it on the Neth box. Stuff like the default firewall, SELinux, and the very limited default Apache install (it doesn’t even include mod_ssl) are things I wouldn’t need to deal with if I’d just put it on the Neth box in the first place.

2 Likes

Nice one, finally the disccuion i really been waiting for
join with SSO USer Federation in nethserver (gluu,keycloack,privacyID3A) - Feature - NethServer Community

Still TBD. I’m not at all sure what you mean by “user federation”, and it seems that the application you have in mind requires two-way user sync–I don’t think any of these solutions can handle that, at least not in a way appropriate to Nethserver.

OK, I have LemonLDAP::NG authenticating against OpenLDAP running on a Neth server. I’d expect a very similar procedure to work for AD, but I haven’t tested that yet.

Installation

  • Install LLNG per their docs. Include the sed step to replace example.com in all the config files with your domain.
  • yum install lasso lasso-perl
  • In the Neth server manager, make sure the admin user is active–reset the password if necessary.
  • Obtain cert(s) covering auth.yourdomain, manager.yourdomain, test1.yourdomain, test2.yourdomain
  • Set up DNS so that auth.yourdomain, manager.yourdomain, test1.yourdomain, and test2.yourdomain resolve to your Neth server
  • Implement HTTPS redirection for LLNG (adapted from @mrmarkuz’ config for Peertube). Edit /etc/httpd/conf.d/z-lemonldap-ng-portal.conf and z-lemonldap-ng-manager.conf to include (this configuration will give an A rating with SSLLabs):
# It's generally not a good idea to broadcast the version of Apache you run
ServerSignature Off
ServerTokens Prod

# Security configuration
SSLCipherSuite                    EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol                       All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder               on
# Requires Apache >= 2.4
SSLCompression                    off
# To use stapling, we have to enable it globally
SSLStaplingCache                  "shmcb:logs/stapling-cache(150000)"
# OCSP Stapling requires Apache >= 2.3.3
SSLUseStapling                    on
SSLStaplingResponderTimeout	  5
SSLStaplingReturnResponderErrors  off
SSLSessionTickets                 off # Requires Apache >= 2.4.11

# Manager virtual host (auth.yourdomain)
<VirtualHost *:80 [::]:80>
        ServerName auth.yourdomain
        ServerAdmin webmaster@yourdomain
#        Protocols h2c http/1.1

        RewriteEngine On
        RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

        Alias /.well-known/acme-challenge/ /var/www/certbot/
        <Directory /var/www/certbot>
                Options None
                AllowOverride None
                ForceType text/plain
                RedirectMatch 404 "^(?!/\.well-known/acme-challenge/[\w-]{43}$)"
                Require method GET POST OPTIONS
        </Directory>

        ErrorLog "/var/log/httpd/manager.error.log"
        CustomLog "/var/log/httpd/manager.access.log" common env=!dontlog
</VirtualHost>


<VirtualHost *:443 [::]:443>
    ServerName auth.yourdomain
    LogLevel notice
    # See above to set LLNG user id in Apache logs
    #CustomLog /var/log/httpd/manager.log llng
    #ErrorLog /var/log/httpd/lm_err.log

    SSLEngine on
    # For example with certbot (you need a certificate to run https)
    SSLCertificateFile /etc/letsencrypt/live/manager.yourdomain/cert.pem
    SSLCertificateChainFile /etc/letsencrypt/live/manager.yourdomain/chain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/manager.yourdomain/privkey.pem

Set Portal URL to SSL and enforce secure cookie

  • Log in as user dwho with password dwho. Sadly it doesn’t make any TARDIS sounds on login, but it should direct you to a portal page:

  • Click on the WebSSO Manager, which will bring you to the configuration page:

  • In the left gutter, under General Parameters, expand Portal, and then select URL. Edit the value to specify HTTPS (https://auth.yourdomain)

  • Back in the left gutter, under General Parameters, expand Cookies, then click on Secured Cookie (SSL). In the drop-down, select Secured Cookie (SSL)

  • Click Save at the top of the screen, enter a description if desired, and save your work.

Configure LLNG to authenticate to the Neth OpenLDAP server

  • In the left gutter, expand Virtual Hosts, then manager.yourdomain, and click on Access rules.
  • Change each of the rules to add or $uid eq "admin" at the end.
  • Do not click Save yet
  • Back in the left gutter, expand General Parameters, then click on Authentication parameters.
  • Set Authentication module to LDAP, and Register module to None.
  • Do not click Save yet
  • Back in the left gutter, under General Parameters, under Authentication parameters, expand LDAP parameters, then click on Connection.
    • Set Verify LDAP server certificate to Optional
    • Set Users search base to dc=directory,dc=nh
    • Set Account to cn=ldapservice,dc=directory,dc=nh
    • Set Password to your LDAPService password (you’ll find it in the Neth server manager, under Users & Groups, in the details for the Local LDAP account provider)
  • Now, at the top of the page, click Save. Enter a comment if desired, then click OK.
  • Log out (under the menu in the upper-right corner)

Test

  • Browse back to http://auth.yourdomain
  • Log in as your admin user with the password for that user. You should see the same portal you saw previously when you logged in as dwho.
  • Log out, and log back in as some other user on your Neth system. You should see a different portal page, without the WebSSO Manager or related buttons.
6 Likes

Now we’re going to configure Nextcloud to authenticate to LemonLDAP::NG. This follows the LLNG docs pretty closely.

  • First, in the LLNG Manager (manager.yourdomain), enable the SAML 2.0 issuer module. In the left gutter, expand General Parameters, Issuer modules, SAML, then click on Activation. Set to On.
  • Back in the left gutter, expand SAML2 Service, then Security parameters, then click on Signature. Click the New certificate link near the top of the page. Copy the certificate from the Public Key field on this page.
  • Now, in Nextcloud, add/enable the SSO & SAML authentication app.
  • Still in Nextcloud, logged in as admin, go to the Settings page, then to SSO & SAML authentication. Click the button to use the built-in SAML authentication. Enter the parameters.
    • In the first field under General (with the default text of Attribute to map the UID to), enter uid
    • Under Identity Provider Data, in the first field, enter https://auth.yourdomain/saml/metadata
    • In the second field, enter https://auth.yourdomain/saml/singleSignOn.
    • Expand the optional Identity Provider settings
    • In the third field, enter https://auth.yourdomain/saml/singleLogout
    • Ignore the fourth field
    • In the fifth field, paste the certificate you copied above.
    • Download the metadata XML file to a convenient location.
    • Note the warning at the top of the page–this will lose access to the built-in Nextcloud admin user unless you browse directly to https://$nextcloud_URL/index.php/login?direct=1.
  • Back to the LLNG Manager. In the left gutter, click on SAML Service Providers, then click Add SAML SP at the top. Give it a descriptive name (like “Nextcloud”) and click OK.
  • Below SAML Service Providers, expand the new entry for Nextcloud, and click on Metadata. Upload the file you downloaded from Nextcloud (should be named metadata.xml), or paste in its contents.
  • Back in the left gutter, below Metadata, click on Exported attributes. At the top, click on Add attribute, and add two attributes. For the first, both the Variable name and Attribute name should be cn; for the second, they should both be uid.
  • Back in the left gutter, two lines down, expand Options, then click on Signature. Set both Check SSO message signature and Check SLO message signature to Off.
  • Save your work.

Test

Browse to your Nextcloud URL. You’ll be directed to the LLNG authentication portal. Enter a user’s uid/password there and log in, whereupon you’ll be directed back to Nextcloud and logged in as that user.

Notes

  • As I mention above, this doesn’t give you access to an admin user for Nextcloud. No doubt there’s a way to address this, but I haven’t gotten to it yet.
  • This logs the user in as his username, rather than the UUID that’s normally used internally with Nextcloud when it’s authenticating to Nethserver’s OpenLDAP. I expect this could be addressed by changing the Exported attributes above, perhaps exporting entryUUID as uid–though I have to say, I like the users’ directories to have their usernames rather than UUIDs. But obviously this would be disruptive if done on a system with existing users.

TODO

  • Figure out the admin user
  • Figure out the attribute mapping for the UUID
  • Get Nextcloud to sign the SSO/SLO messages–seems this would have to increase security
  • YubiKey authentication, of course. Yes, I know Nextcloud supports that internally, but I’m using it as a sample app here.
3 Likes

The LLNG docs also describe setting it up to authenticate for Roundcube, but it looks like they depend on Roundcube being in its own virtualhost, which doesn’t appear to be an option with Nethserver. Bother.

Edit: It turns out those docs are also out of date, as they rely on a http_authentication plugin that doesn’t appear to be available any more. There is, however, a plugin for OpenID Connect, which looks like it would work, though I haven’t tested it as yet.

Having played with LLNG a bit now, I have some observations relative to using it with Neth:

  • Its security model really expects that every resource you’ll be protecting is in its own virtual host. You can then add PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2 to the virtual host’s conf file, and LLNG will handle it (and Apache won’t serve it without LLNG saying it’s OK).
  • It kind of expects that users will be able to log into a portal (which it provides), from which they’ll have access to any apps they’re authorized to use–once again, defined as virtual hosts and for which LLNG is configured.
  • That portal also handles password resets. Since it’s from the same folks who wrote self-service password, and SSP seems to work fine, I expect it could safely handle users’ password resets on Neth–but I haven’t tested this.
  • I like that, compared to most of the other systems I compared it against, it doesn’t require Java, its own container, or a reverse proxy configuration. I don’t know that Perl is a plus, as such, but plenty of e-smith/SME/Neth is already written in Perl, so…
  • It was relatively straightforward to connect with Neth’s OpenLDAP system, and then authenticate those users.
  • I don’t know if it’s unique in this capability, but I didn’t see any of the other contenders mention their ability to authenticate using HTTP headers. This apparently allows LLNG to handle the authentication for any application that can use external authentication (a/k/a “Apache authentication”), which should make it easier to integrate with software that doesn’t support technologies like OIDC or SAML. It’s as yet unclear to me whether Cockpit or WebTop could be used with this or any other mechanism supported by LLNG.
  • This could be a deal-breaker–it looks like it would be a nightmare to template. The main .ini file wouldn’t be bad at all, and of course Apache’s virtualhost .conf files would be straightforward enough. But there are a few problems with the main configuration file:
    • LLNG keeps the last several config files on disk, making it easy to roll back to a previous config file if you break something (which I’ve done a lot). Don’t think that could be templated very easily.
    • The config file, at least by default, is JSON. I don’t think that’s a deal-breaker by itself, but it seems it could be kind of a messy format to template well. It does support YAML as well, though, if that would make things easier.
    • LLNG comes with its own web control panel (the so-called manager), which lets you control a lot of stuff. And you need to use it to add clients/relying parties and other such things. Unless we’re going to write all of it into the e-smith database structure, and code a UI to control it, we have to leave the manager there, and that means we’re not going to have any real control over the contents of the config file.
    • I think the upshot is that we could ship a preconfigured file, set up with the basic Neth applications, configured to handle their authentication, handle the correct authentication backend (local/remote OpenLDAP, AD, etc.), but then the user/admin needs to work directly with the manager. That would also mean that, whatever form that file took, it couldn’t be an ordinary template that got overwritten under normal circumstances.
    • There’s a lemonldap-ng-cli tool that will noninteractively edit the config file, and may mitigate some of these concerns. It still wouldn’t make it something that could be readily templated, but it should be relatively straightforward to script changes to the configuration (see, e.g., these instructions dealing with Gerrit)

@giacomo, thoughts?
@oneitonitram, how does this line up with what you were wanting to do?

5 Likes