How to implement Single Sign-On

I have a mobile app that uses AWS Cognito to authenticate users. I wanted integrate the app with FarmOS such that users could sign in with the same credentials. I’m looking for a good way to solve this authentication puzzle.

One option I found was this: Cognito | Drupal.org
But when I try installing it with composer require 'drupal/cognito:^2.1' I get this error.

  Problem 1
    - Root composer.json requires symfony/finder ^4.0, found symfony/finder[v4.0.0-BETA1, ..., 4.4.x-dev] but the package is fixed to v5.4.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
  Problem 2
    - Root composer.json requires drupal/core-dev 9.3.7 -> satisfiable by drupal/core-dev[9.3.7].
    - drupal/core-dev 9.3.7 requires symfony/finder ^4.4 -> found symfony/finder[v4.4.0-BETA1, ..., 4.4.x-dev] but the package is fixed to v5.4.3 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.

I’m able to brute force it by adding --with-all-dependencies, but is that safe?

Another option I considered is OpenID Connect / OAuth client | Drupal.org. I think can make that work but the flow is more complicated. Users must click “Sign in with …” and go to a separate page to login. I was hoping to make this more seamless for users.

Also, I noticed that these authentication modules only work on /user/login but FarmOS seems to use a separate authentication form. Is that correct?

The final option I considered was to totally flip the authentication scheme around. Use FarmOS as the identity provider. Make users sign in to the app using their FarmOS credentials.
Thats not the design I had in mind but if thats the best solution I might be willing to make the switch.

Are there any helpful suggestions for how to tackle this problem?

Glad to hear you’re digging into this @gmagnusson! SSO has been a hot topic recently in the OpenTEAM community. I will actually be giving a quick presentation in two weeks about these exact options you outlined. However, I have not tried to do any of this myself, so it is just theory.

The farmOS-based project I’m working on with USDA is also going to be using SSO (with the USDA’s eAuth identity provider), and the contractors working on it landed on using the OpenID Connect module to accomplish it. I’m not familiar with the specifics at this point though. I think it would be worth you exploring that and documenting your findings - as it would contribute to the public knowledge and discussion around these options! I’d like to understand all of it better myself.

I’m not familiar with Cognito, but I would probably prefer a more generic approach that isn’t tied to a particular provider, if possible. Even if that means a less-than-perfect user experience. If we are going to provide any “official” recommendations or documentation on this topic for the farmOS community (which I would love to see happen!) then it needs to be as “open source” as possible. :wink:

I’m able to brute force it by adding --with-all-dependencies, but is that safe?

I’m not sure why you’re getting that error - but yea I would be careful running --with-all-dependencies without understanding the root cause of the issue first.

Also, I noticed that these authentication modules only work on /user/login but FarmOS seems to use a separate authentication form. Is that correct?

Not sure I know what you mean. farmOS uses the default Drupal login (/user/login).

The final option I considered was to totally flip the authentication scheme around. Use FarmOS as the identity provider.

Yea this is another option, and I’d love to be able to document how to do both approaches for anyone who is interested!

Would love to see what you learn in the process - good luck!

1 Like

Regarding this specifically… we do pin the symfony/finder package version here: https://github.com/farmOS/farmOS/blob/29106edda9951d01b47abe0034282bac0abd4387/composer.project.json#L10

The commit that adds that explains a bit: Include symfony/finder in require-dev to fix version pinning issue wh… · farmOS/farmOS@b0a45f3 · GitHub

You might be interested in this thread too: Using farmOS 2.x as a OAuth2 Authorization Server (It’s the reverse case, but mildly related)

2 Likes

Sounds like I’m out on the bleeding edge :stuck_out_tongue:
I’ll probably abandon the Cognito module unless I choose to take over the maintenance of it. It does not have any recent activity.
I’ll keep exploring the other two options. I’m happy to share my findings here.

My project is actually also USDA funded, but I had not heard of eAuth. I’m sure they would appreciate the synergy if I manage to connect it to both FarmOS and eAuth. I need to look into that.

Perhaps I’m describing it wrong.
If I go to my root domain and I’m not authenticated I see this

If I go to myDomain/user/login I see

The modules I tried installing only seem to affect the second form. I can’t tell if that because of how the modules are built or because of how FarmOS is setup.

1 Like

Thank you! I think that will be very helpful.

I forgot you did this @Symbioquine! Thanks for connecting to that thread.

Oh interesting! My understanding is eAuth is required in any cases where the USDA is requiring users to sign into their services (eg: their websites and apps). Since an instance of farmOS is going to be hosted in a USDA environment and users will be logging into it, it needs to go through eAuth. But I imagine that’s not a requirement for your project, if it’s not part of USDA.

The modules I tried installing only seem to affect the second form. I can’t tell if that because of how the modules are built or because of how FarmOS is setup.

Oh I see what you mean now.

Yea, so farmOS does add a bit of customization in that regard. It was added here: https://www.drupal.org/project/farm/issues/3177199

I am new here, learning the ropes. I work with @mstenta on this USDA project that implements an OpenIDConect client and have worked on many USDA projects.

Mike is correct, when authentication is involved for any USDA sponsored website it must be via eAuth. EAuth is their Oauth2 implementation. It will work with an OpenIDConnect client, can be used by a web agent or SAML client. Sometimes the client is built into the application and other times it is implemented somewhere upstream in the network such as in a reverse proxy server.

Oauth2 seems to be a very standard type of authentication mechanism. I am not sure of the term to use there so take my use of mechanism lightly; maybe protocol, system or some other term is a better fit.

I believe that Google and Facebook authentication are also Oauth2 based. I am not familiar with AWS Cognito but maybe it is also Oauth2 based. I only mention this in case if helps in research when searching about information, if you see Oauth2 mentioned in the AWS Cognito information then the Drupal OpenIDConnect module or the SAML module may be what you are looking for to integrate with it.

One thing that confused us for a while was that as Mike mentioned there are two directions for authentication, one is when you are the source of authentication and the other is when you are the subject of it. We worked on the wrong direction for some time before we realized the difference. In Drupal Admin the configuration for each is in a different location. When we stumbled onto OpenID Connect configuration, we were unlucky in that it was the wrong direction, and we were not yet aware of that and so everything we did to try and make that work was a waste of time.

Hope this might help.

1 Like

I just finished installing farmOS and wanted to integrate it with my SSO system (powered by authentik). At a first glance, following the Drupal OAuth Login Setup Guide seems to have worked without any issues.

I’ve yet to try anything more complicated (e.g. role mapping), but wanted to share in case this helps anybody else.

3 Likes

Thanks for the input @ppetru - I hadn’t heard of that module before. And welcome to the forum! :slight_smile:

1 Like

Welcome, I have also installed it, role mapping and other more advanced feature seems to be paid features though so I also haven’t looked into it more than that.

For other folks who run into this, I wanted to share some interesting details;

  • I would recommend staying away from the plugins developed by the “miniOrange” company. (Including the one referenced by that guide above.) They may work well (I don’t really know) but I found their sales strategy of publishing freeware modules and documentation mixed in with Drupal’s - generally free - ecosystem, disingenuous.
  • Instead, consider the openid_connect module and possibly some of the plugins that extend it.

Here’s what I did to set up farmOS to authenticate with Keycloak;

Module installation

composer require 'drupal/openid_connect:^1.4'
drush en openid_connect

composer require 'drupal/keycloak:^1.8'
drush en keycloak

Keycloak Configuration

Groups

Create groups for each of the roles in farmOS. farmos_manager, farmos_viewer, etc.

Client / Client Groups Mapper

Configure a new OAuth client in Keycloak and add a custom groups mapper under its dedicated client scope;

image

Don’t forget to copy the client secret from the credentials tab for the next step…

farmOS configuration

Under the OpenID Connect configuration at https://farmos.test/admin/config/services/openid-connect;

Or via drush;

drush config:set -y --input-format=yaml openid_connect.settings ? "
always_save_userinfo: true
connect_existing_users: true
override_registration_settings: true
user_login_display: replace
userinfo_mappings:
  timezone: zoneinfo
"

drush config:set -y --input-format=yaml openid_connect.settings.keycloak ? "
enabled: true
settings:
  client_id: farmos
  client_secret: ERAvaJhmFq6N8okacpIBaTrDMBl2ADLp
  keycloak_base: 'https://login.farmos.test'
  keycloak_realm: kirchoff_farm
  userinfo_update_email: true
  keycloak_groups:
    enabled: true
    claim_name: groups
    split_groups: false
    split_groups_limit: '0'
    rules:
      -
        id: 3c128a59-f2ce-463b-9e67-8d5b6516116e
        role: farm_manager
        action: add
        operation: regex
        pattern: farmos_manager
        case_sensitive: false
        weight: 0
        enabled: true
      -
        id: ecfe635f-d2e5-4e6c-8336-f1ab90f17270
        role: farm_manager
        action: remove
        operation: not_regex
        pattern: farmos_manager
        case_sensitive: false
        weight: 0
        enabled: true
      -
        id: fce61742-011c-46c2-b7b6-1b372fec3321
        role: farm_worker
        action: add
        operation: regex
        pattern: farmos_worker
        case_sensitive: false
        weight: 0
        enabled: true
      -
        id: 6bb6d978-9c23-477b-8b04-6b95391ac931
        role: farm_worker
        action: remove
        operation: not_regex
        pattern: farmos_worker
        case_sensitive: false
        weight: 0
        enabled: true
      -
        id: 5e1aa944-d04e-42f0-b13a-8b15dbe480de
        role: farm_viewer
        action: add
        operation: regex
        pattern: farmos_viewer
        case_sensitive: false
        weight: 0
        enabled: true
      -
        id: 911a05cf-bfc2-4030-893c-e0963b9e41c9
        role: farm_viewer
        action: remove
        operation: not_regex
        pattern: farmos_viewer
        case_sensitive: false
        weight: 0
        enabled: true
  keycloak_sso: true
  keycloak_sign_out: true
  check_session:
    interval: 2
  redirect_url: ''
  keycloak_i18n_enabled: false
  check_session_enabled: 0
  keycloak_groups_enabled: 0"

Clear Cache

The OpenID Connect module doesn’t seem to invalidate the login page cache correctly so a cache rebuild is needed before you’ll see the changes on the login page.

drush cr

/403 Login Issue

There’s an issue where logins will (almost) always end up on a access denied page upon successful login. https://www.drupal.org/project/farm/issues/3455977

The work-around is to install the r4032login module that makes all the logins occur via the /user/login page.

composer require 'drupal/r4032login:^2.2'
drush en r4032login

farmos.test note

I’m using the domains login.farmos.test & farmos.test with self-signed certificates so I needed to configure the root CA so that Drupal could make requests directly to Keycloak over https. This isn’t needed in production with real certificates of course.

php.ini

[curl]
curl.cainfo = "/localRootCA.pem"

docker-compose.yml

...
  www:
    ...
    volumes:
      ...
      - './devcerts/rootCA.pem:/localRootCA.pem'
...

Result

image

4 Likes