pantheon-systems / wp-saml-auth

Rock-solid SAML authentication for WordPress built on a modern foundation.
https://wordpress.org/plugins/wp-saml-auth/
89 stars 44 forks source link

Consider disabling user editing for SAML-provisioned users #15

Open danielbachhuber opened 8 years ago

danielbachhuber commented 8 years ago

If a user was created through the SAML IDP, we may want to consider having a feature where user editing is disabled for SAML-provisioned users.

Similarly, we may want to update the details for a SAML-provisioned user each time they log in through their IDP.

danielbachhuber commented 8 years ago

we may want to consider having a feature where user editing is disabled for SAML-provisioned users.

Because per-field edit capabilities isn't really tenable in WordPress, we could instead filter map_meta_cap and disable editing of the user entirely.

dsmith-wustl commented 2 years ago

The Shibboleth plugin has a couple clever workarounds for this, that I'm adapting for a planned switchover from that plugin to this one. (So all the code below will be a weird mix of code for this plugin, and code from that one, because I haven't written and tested it all yet.)

When a user is created, they drop a user_meta note to track if the user was created via their plugin. Here you could do something like:

add_action( 'wp_saml_auth_new_user_authenticated', function ( $user_id ) {
  update_user_meta( $user_id, 'created_by_saml', true);
} );

(There's an edge case here where a "local" user with the same username as a SAML user might not get this flag set properly. As an example, part of my new-site process involves creating several users whose usernames match their SAML usernames, prior to installing and activating SSO. Maybe add the same hook to wp_saml_auth_existing_user_authenticated too?)

Then, if a user was created this way, first you use a bit of JavaScript to disable the relevant fields.

add_action( 'admin_init', function() {
  disable_field_edits();
});

function disable_field_edits() {
  $user = wp_get_current_user();
  if (get_user_meta( $user->ID, 'created_by_saml' ) == true ) {
    add_filter( 'show_password_fields', '__return_false' );
    add_action( 'admin_enqueue_scripts', function( $hook ) {
      if ('profile.php' != $hook ) {
        return;
      }
      wp_enqueue_script( 'saml-user-edit', plugin_dir_url(__FILE__) . 'user-edit.js' );
    });
  }
}
jQuery(document).ready(function($) {
  jQuery("#first_name").attr("disabled", true);
  jQuery("#last_name").attr("disabled", true);
  jQuery("#email").attr("disabled", true);
  jQuery("#first_name").parents(".form-table").before("<div class=\"updated fade\"><p>Some profile fields cannot be changed from WordPress.</p></div>");
  jQuery("#email-description").hide();
});

(The Shibboleth plugin makes this a bit more complicated, since it allows you to specify, for each managed field, whether a user should be allowed to edit it. For me, an all-or-nothing is sufficient.)

Also, just in case a user gets clever and disables JavaScript (thus making the form fields edit-able by the client again), hook into the actual form submission and change the values back before submitting:

add_action( 'personal_options_update', 'shibboleth_prevent_managed_fields_update' );
add_action( 'edit_user_profile_update', 'shibboleth_prevent_managed_fields_update' );

function shibboleth_prevent_managed_fields_update( $user_id ) {
  if ( get_user_meta( $user_id, 'created_by_saml' ) ) {
    $_POST['first_name'] = $user->first_name;
    $_POST['last_name'] = $user->last_name;
    $_POST['email'] = $user->user_email;
  }
}

I suppose the question here, is whether this is something that comes up often enough that it should be made into a checkbox in this plugin, as opposed to having users implement it themselves. Which is a valid question! There are good arguments both ways.