Wildcard email whitelists in WordPress and BuddyPress

WordPress (and before that WPMU) has long had a feature that allows admins to set a whitelist of email domains for registration (Limited Email Registration). On the Commons, we need to account for a lot of different domains, some of which are actually dynamic – but they are all of the form *.cuny.edu. WP doesn’t support this kind of wildcards, but we’ve got it working through a series of customizations.

These first two functions form the heart of the process. The first one hooks to the end of the BP registration process, looks for email domain errors, and then sends the request to the second function, which does some regex to check against the wildcard domains you’ve specified. This is BP-specific, but I think you could make it work with WPMS just by changing the hook name.


function cac_signup_email_filter( $result ) {
	global $limited_email_domains;

	if ( !is_array( $limited_email_domains ) )
		$limited_email_domains = get_site_option( 'limited_email_domains' );
	
	$valid_email_domain_check = cac_wildcard_email_domain_check( $result['user_email'] );	
	
	if( $valid_email_domain_check ) {
		if ( isset( $result['errors']->errors['user_email'] ) )
			unset( $result['errors']->errors['user_email'] );
	}
	
	return $result;
}
add_filter( 'bp_core_validate_user_signup', 'cac_signup_email_filter', 8 );

function cac_wildcard_email_domain_check( $user_email ) {
	global $limited_email_domains;
	
	if ( !is_array( $limited_email_domains ) )
		$limited_email_domains = get_site_option( 'limited_email_domains' );

	if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) { 
		$valid_email_domain_check = false;
		$emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) );
		foreach ($limited_email_domains as $limited_email_domain) {
			$limited_email_domain = str_replace( '.', '\.', $limited_email_domain);        // Escape your .s
			$limited_email_domain = str_replace('*', '[-_\.a-zA-Z0-9]+', $limited_email_domain);     // replace * with REGEX for 1+ occurrence of anything
			$limited_email_domain = "/^" . $limited_email_domain . "/";   // bracket the email with the necessary pattern markings
			$valid_email_domain_check = ( $valid_email_domain_check or preg_match( $limited_email_domain, $emaildomain ) );
		}
	}	

	return $valid_email_domain_check;
}

Before WP 3.0, this was enough to make it work. The latest WP does increased sanitization on the input of the limited_email_domains field, however, which makes it reject lines like *.cuny.edu. The following functions add an additional field to the ms-options.php panel that saves the limited domains without doing WP’s core checks. (Beware: bypassing WP’s checks like this means that there are no safeguards in place for well-formedness. Be careful about what you type in the field, or strange things may happen.)


function cac_save_limited_email_domains() {
	if ( $_POST['cac_limited_email_domains'] != '' ) {
		$limited_email_domains = str_replace( ' ', "\n", $_POST['cac_limited_email_domains'] );
		$limited_email_domains = split( "\n", stripslashes( $limited_email_domains ) );
	
		$limited_email = array();
		foreach ( (array) $limited_email_domains as $domain ) {
				$domain = trim( $domain );
			//if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.])+$|', $domain ) )
				$limited_email[] = trim( $domain );
		}
		update_site_option( 'limited_email_domains', $limited_email );
	} else {
		update_site_option( 'limited_email_domains', '' );
	}
}
add_action( 'update_wpmu_options', 'cac_save_limited_email_domains' );

function cac_limited_email_domains_markup() {
	?>
	
	<h3><?php _e( 'Limited Email Domains That Actually Work' ); ?></h3>
	
	<table class="form-table">
	<tr valign="top">
		<th scope="row"><label for="cac_limited_email_domains"><?php _e( 'Limited Email Registrations' ) ?></label></th>
		<td>
			<?php $limited_email_domains = get_site_option( 'limited_email_domains' );
			$limited_email_domains = str_replace( ' ', "\n", $limited_email_domains ); ?>
			<textarea name="cac_limited_email_domains" id="limited_email_domains" cols="45" rows="5">< ?php echo wp_htmledit_pre( $limited_email_domains == '' ? '' : implode( "\n", (array) $limited_email_domains ) ); ?>
			<br />
			<?php _e( 'If you want to limit site registrations to certain domains. One domain per line.' ) ?>
		</td>
	</tr>
	</table>
	
	<?php
}
add_action( 'wpmu_options', 'cac_limited_email_domains_markup' );

4 thoughts on “Wildcard email whitelists in WordPress and BuddyPress”

  1. Question: Why add the necessary processing for handling wildcards like *.cuny.edu? Why not simply adjust your code so that all domains are allowed to be wildcard at the beginning of them? So that, for example, “cuny.edu” is treated as “*.cuny.edu” at all times, for all domains that you enter. This way, you don’t need the extra code to have a special field to put your domains in.

  2. Hi,

    Perhaps you can clarify this. The latest versions of WP and WPMS supports emai/domain whitelist where only admin or super admin preferred email/domains will be able to register.

    If this is accurate, is it native to WP or do I need a plugin for it? I need something to restrict sign ups except for certain emails and domains. I am assuming this will add more security, right?

Leave a Reply

Your email address will not be published. Required fields are marked *

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image