Skip to content

Instantly share code, notes, and snippets.

@littlefyr
Created June 13, 2013 17:35
Show Gist options
  • Save littlefyr/5775652 to your computer and use it in GitHub Desktop.
Save littlefyr/5775652 to your computer and use it in GitHub Desktop.
<?php
class FrozenSso {
protected $plugin_slug = 'frzn-sso';
protected $auth_secret = 'super secret string :)';
protected static $instance = null;
protected $plugin_screen_hook_suffix = 'FrozenSso';
private function __construct() {
if ( NULL <> $this->auth_secret && !defined( 'FRZN_SSO_SECRET' ) )
define( 'FRZN_SSO_SECRET', $this->auth_secret );
//setup custom URLs
add_action('parse_request', array($this, 'parse_request'), $accepted_args = 1 );
add_action('init', array($this, 'do_rewrite'));
add_action('send_headers', array($this, 'add_cors_headers'));
}
public static function get_instance() {
// If the single instance hasn't been set, set it now.
if ( null == self::$instance ) {
self::$instance = new self;
}
return self::$instance;
}
public static function activate( $network_wide ) {
self::add_rewrite_rule();
flush_rewrite_rules( true );
}
public static function deactivate( $network_wide ) {
// TODO: Define deactivation functionality here
flush_rewrite_rules( true );
}
public function do_rewrite()
{
self::add_rewrite_rule();
}
public static function add_rewrite_rule()
{
global $wp_rewrite;
add_rewrite_tag( '%sso%', '!|([a-zA-Z0-9_-]+)' );
}
public function parse_request($wp)
{
// only process requests with sso query_var
if (array_key_exists('sso', $wp->query_vars)) {
$action = $wp->query_vars['sso'];
switch ($action) {
case '!':
$this->get_session_token();
break;
default:
// do the login
$this->do_login($action);
break;
}
}
}
public function get_session_token() {
$username = $_POST['username'];
$password = $_POST['password'];
$redirect = $_POST['redirect_url'];
$data = new StdClass;
$this->add_cors_headers();
header('Content-Type: application/json');
$user = wp_authenticate_username_password( null, $username, $password );
if (is_wp_error($user)) {
$data->success = false;
$data->errors = $user->get_error_codes();
} else {
$usr = new StdClass;
$usr->username = $username;
$usr->expiry = strtotime('+ 1 day');
$usr->redirect = $redirect;
$usr->sig = sha1( json_encode($usr) . FRZN_SSO_SECRET );
$usr_string = json_encode( $usr );
$usr_string = $this->base64url_encode( $usr_string );
// $usr_string = $this->encrypt_string($usr_string);
$data->success = true;
$data->uri = home_url( '?sso=' . $usr_string);
}
echo(json_encode($data));
die();
}
public function do_login($token)
{
$this->add_cors_headers();
header('Content-Type: application/json');
$token = $this->base64url_decode($token);
$data = json_decode($token);
$token_sig = $data->sig;
unset($data->sig);
$calc_sig = sha1( json_encode($data) . FRZN_SSO_SECRET );
$out = new StdClass;
if ($token_sig == $calc_sig && $data->expiry >= time()) {
add_filter('authenticate', array($this, 'token_authentication'), 41, 3);
$user = wp_signon( array( 'user_login' => $data->username, 'user_password' => $token_sig, 'rememberme' => false));
// global $auth_secure_cookie;
// var_dump($auth_secure_cookie);
if (is_wp_error( $user )) {
$out->success = false;
$out->errors = $user->get_error_codes();
} else {
$redirect =$data->redirect;
if (!empty($redirect)) {
wp_safe_redirect( $redirect );
die();
}
$out->success = true;
$out->userID = $user->ID;
}
} else {
$out->success = false;
$out->errors = array('invalid_token');
}
echo(json_encode($out));
die();
}
public function token_authentication($user, $username, $password)
{
if ( is_a($user, 'WP_User') ) { return $user; }
// This function is added to the filters ONLY if the token has
// passed the test in do_login so no need to revalidate
$user = get_user_by('login', $username);
//This is taken from the core wp_authenticate_username_password code http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/user.php#L72
if ( !$user )
return new WP_Error('invalid_username', sprintf(__('<strong>ERROR</strong>: Invalid username. <a href="%s" title="Password Lost and Found">Lost your password</a>?'), wp_lostpassword_url()));
if ( is_multisite() ) {
// Is user marked as spam?
if ( 1 == $user->spam)
return new WP_Error('invalid_username', __('<strong>ERROR</strong>: Your account has been marked as a spammer.'));
// Is a user's blog marked as spam?
if ( !is_super_admin( $user->ID ) && isset($user->primary_blog) ) {
$details = get_blog_details( $user->primary_blog );
if ( is_object( $details ) && $details->spam == 1 )
return new WP_Error('blog_suspended', __('Site Suspended.'));
}
}
return $user;
}
public function add_cors_headers() {
//TODO: change the allowed origins to be taken from a setting set in the
header("Access-Control-Allow-Origin: *");
}
private function create_hash() {
return substr( sha1( FRONT_END_COOKIE_SSO_SECRET ), 0, 32 );
}
private function encrypt_string( $text ) {
$salt = $this->create_hash();
return trim( $this->base64url_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND ) ) ) );
}
private function decrypt_string( $text ) {
$salt = $this->create_hash();
return trim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $salt, $this->base64url_decode( $text ), MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB ), MCRYPT_RAND ) ) );
}
//base64 encoding does not produce values that work well in URLs so we
// replace the + with - and / with _ and add the = padding on decode
// taken from http://us.php.net/manual/en/function.base64-encode.php#103849
private function base64url_encode($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
private function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}
}
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
// TODO: replace `class-frzn-sso.php` with the name of the actual plugin's class file
require_once( plugin_dir_path( __FILE__ ) . 'class-frzn-sso.php' );
// Register hooks that are fired when the plugin is activated, deactivated, and uninstalled, respectively.
register_activation_hook( __FILE__, array( 'FrozenSso', 'activate' ) );
register_deactivation_hook( __FILE__, array( 'FrozenSso', 'deactivate' ) );
FrozenSso::get_instance();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment