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

SAML JIT Provisioning #3389

Merged
merged 6 commits into from Nov 8, 2021
Merged

SAML JIT Provisioning #3389

merged 6 commits into from Nov 8, 2021

Conversation

FoxAmes
Copy link
Contributor

@FoxAmes FoxAmes commented Sep 9, 2021

Hey all,

Gonna start this by saying I am absolutely not a PHP dev. That out of the way, our use case for phpIPAM involves creating accounts for a constantly-changing set of users, SAML allows us to avoid managing authentication, but without SCIM or JIT, we still need to provision several dozen or even hundred accounts manually, which is not desirable.

I've taken a crack at basic JIT for SAML here- it works for our use case, but is far from comprehensive or perfect. I am not familiar enough with the phpIPAM codebase to know if there is a more idiomatic way of dealing with this, but without having an Admin in scope it looks like direct database modification is the only method.

The core idea for JIT is that users are automatically created or updated based on information passed from the IdP.

Finally, I couldn't find any place to update documentation for features like this, but I'd happily do so if anyone could show me where. In particular, this implementation requires 3 additional attributes from the SAML IdP: display_name, role, and email.

Feedback would be greatly appreciated.

@GaryAllan
Copy link
Collaborator

Hello @FoxAmes
How are you handling group membership for non-admins?

@FoxAmes
Copy link
Contributor Author

FoxAmes commented Sep 15, 2021

@GaryAllan Good point, honestly hadn't considered it. I've added parsing a CSV string from the groups attribute. I've also taken a look at #3221 and followed that methodology for user creation, which removes the duplicate DB management snippets.

@FoxAmes
Copy link
Contributor Author

FoxAmes commented Oct 8, 2021

Any updates on this? I'd love to do what I can to get this feature upstreamed, and I'm happy to make what changes I'm capable of to get it ready!

@GaryAllan
Copy link
Collaborator

Hello,

Thanks for PR. I'll review fully in the next week or so.

Quick glance it looks reasonable, may benefit from more paranoia e.g. It edits an account if it already exists but doesn't check if the existing account is a SAML account...it could wallop the local admin account or overwrite accounts from other authentication methods.

Longer term I would like authentication without the need for local accounts at all (AD/LDAP/SAML/TACACS/RADIUS).

@GaryAllan GaryAllan self-assigned this Oct 15, 2021
@GaryAllan GaryAllan marked this pull request as draft October 17, 2021 13:27
@GaryAllan
Copy link
Collaborator

Hi @FoxAmes

I've tested this with KeyCloak and most of the getAttribute() values used in the PR are not included by default. "role" attribute is present but is used for a different purpose.

email was simple to add. display_name doesn't exist, given (first) and surname are available as separate attributes but I haven't figured out how to merge them into a single display_name attribute in the response yet.

For this to be useful for everyone and not just your specific SAML setup; there needs to be a way of specifying which attribute names to use when creating/editing users. There's no guarantee that the email data is stored in an attribute called "email" or that this attribute is included at all.

Plus some documentation so people can figure it out by themselves.

This needs more work so I've changed the status to Draft. I like the idea and will work on this PR.

@FoxAmes
Copy link
Contributor Author

FoxAmes commented Oct 17, 2021

@GaryAllan yep, you're absolutely correct, this requires some custom attributes. I'm using this internally with OKTA and had to build out the attributes in the SAML scheme for the app.

I'm not a SAML expert, but after taking a quick look at the OASIS spec I don't think there are any standard defined attributes. The names of the attributes are fairly inconsequential, I just went with what made sense to me.

I'm happy to add some documentation on what's required for the feature to work, as I mentioned in the initial PR though I'm not sure where that goes. This implementation could do with checking the attributes exist before attempting the account creation, though.

As for the clobbering of existing local accounts- that was intentional on my part as we had a bunch of existing local accounts we wanted to be automatically mastered by our SAML IdP. It's probably not always desired behavior though, so I'll look at adding a toggle for the behavior- in addition to some guards on the local admin.

Hoping to get to some of these early in the week.

@GaryAllan
Copy link
Collaborator

Hi,

I don't want to automatically modify accounts that aren't already SAML.

If you need to migrate local account to SAML this should be possible with an UPDATE SQL query to change the authentication type to SAML once this is merged.

- Check for presence of mandatory SAML attributes.
- Don't modify non-SAML accounts.
- Remove $values with database defaults.
- Change role to isAdmin(bool) attribute.

TODO:
- module_permissions for non-admin users.
- verify $Admin->object_modify succeeds.
- Make JIT & SAML mapped user mutually exclusive.
  - Rename "isAdmin" attribute to "is_admin".
  - Add "modules" attribue.

  Auto provision users via SAML attributes

   - "display_name", (String), MANDATORY
     Users real name / full name.
     Can not be blank.

   - "email", (String), MANDATORY
     Users email address.
     Can not be blank. Must pass filter_var($email, FILTER_VALIDATE_EMAIL).

   - "is_admin", (Boolean), OPTIONAL, default: 0
     User role, "Administrator" or "Normal User".

   - "groups", (String), OPTIONAL (Admins have admin level access to all groups), default: ""
     Comma separated list of group membership.
     e.g "groups"="Operators,Guests"

   - "modules", (String), OPTIONAL (Admins have admin level access to all modules), default: ""
     Comma separated list of modules with permission level, 0=None, 1=Read, 2=Read/Write, 3=Admin
     "*" can be used to wildcard match all modules.
     e.g The following will assign admin permissions to the vlan module and read permissions to everything else.
         "modules" = "*:1,vlan:3"
@GaryAllan
Copy link
Collaborator

Hello @FoxAmes

I've pushed another commit to this branch, this adds module permissions for non-admins and some cleanups.
I'm happy with the code/functionality. The only thing missing is more documentation but I can add this later.

Can you please test and confirm you are happy and I'll merge?

Regards

        //
        // Auto provision users via SAML attributes
        //
        // - "display_name", (String), MANDATORY
        //   Users real name / full name.
        //   Can not be blank.
        //
        // - "email", (String), MANDATORY
        //   Users email address.
        //   Can not be blank. Must pass filter_var($email, FILTER_VALIDATE_EMAIL).
        //
        // - "is_admin", (Boolean), OPTIONAL, default: 0
        //   User role, "Administrator" or "Normal User".
        //
        // - "groups", (String), OPTIONAL (Admins have admin level access to all groups), default: ""
        //   Comma separated list of group membership.
        //   e.g "groups"="Operators,Guests"
        //
        // - "modules", (String), OPTIONAL (Admins have admin level access to all modules), default: ""
        //   Comma separated list of modules with permission level, 0=None, 1=Read, 2=Read/Write, 3=Admin
        //   "*" can be used to wildcard match all modules.
        //   e.g The following will assign admin permissions to the vlan module and read permissions to everything else.
        //       "modules" = "*:1,vlan:3"

@GaryAllan GaryAllan marked this pull request as ready for review October 31, 2021 21:06
@FoxAmes
Copy link
Contributor Author

FoxAmes commented Nov 8, 2021

@GaryAllan just got a chance to test this- looks great and works well in my testing, though I haven't tried specific user module assignment as that's not in our workflow.

My only concern is the lack of documentation- I'm happy to write it up, where might I do so?

@GaryAllan GaryAllan merged commit cb2abfb into phpipam:master Nov 8, 2021
@GaryAllan
Copy link
Collaborator

Thanks,
I'll add the docs when I figure out where to put them.

@FoxAmes FoxAmes deleted the feat-saml-jit branch November 11, 2021 14:23
4o66 added a commit to 4o66/phpipam that referenced this pull request Nov 22, 2021
* 1.5:
  pull upstream 1.5
  Feature: Warn when php and db schema versions do not match
  Update php-saml (3.6.1) and xmlseclibs (3.1.1) submodules
  SAML JIT Provisioning (phpipam#3389)
  Bugfix: Fix remaining version-check comparisons.
  Bugfix: Fix 'New version available' widget
  Bugfix: 1.5.38 Upgrade SQL syntax error (<=MySQL 5.7)
  Bugfix: 1.5.38 Upgrade SQL syntax error (<=MySQL 5.7). Fixes phpipam#3443
  Feature: dbschema 38
  Refactor: Cleanup upgrade_queries
  Bugfix: Database stored sessions require the php_sessions table to exist (dbversion>=3)
  Update changelog. Fix escape_input()
  Bugfix: SAML return to same page when session expires.
GaryAllan added a commit that referenced this pull request Dec 1, 2021
Add document links to API and SAML dialogue boxes
@GaryAllan
Copy link
Collaborator

Hello @FoxAmes

My only concern is the lack of documentation- I'm happy to write it up, where might I do so?

I've added support for markdown documentation. If you want to contribute documentation please raise a PR for markdown under the /doc folder.

https://github.com/phpipam/phpipam/blob/master/doc/Authentication/SAML2.md

@miro444
Copy link

miro444 commented Dec 28, 2022

Hi, I have a question for this. I know you have implemented the above to allow permission management from the IDP, however, I have a setup where I am only pushing the module permissions for admin user. Then for everyone else, I am leaving it without any.

WHat this does is that it uses default module assignment. I have had a look at this in the past and customized it to my own selection modules, however I am unable to find there this was. It is some file which lists default permissions for these users. COuld you please point me that way?

@GaryAllan
Copy link
Collaborator

Hi

Admin users always have access to all modules, setting this in SAML is only useful for non-admin users

The defaults are in the database schema, look at the users table.

@miro444
Copy link

miro444 commented Dec 28, 2022

Yep I know Admin has access to all. THis is as you say for non-admin users who login via SAML. Ok, i'll check the table. I had for some reason thought it was in one of the config files where you define default permissions which are mapped to SAML group then. ANyway, thanks.

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

3 participants