Skip to content

Commit

Permalink
streamline pkce redirect
Browse files Browse the repository at this point in the history
  • Loading branch information
tamw-wnet committed Sep 18, 2024
1 parent 078cb69 commit a4dbdc5
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 60 deletions.
57 changes: 1 addition & 56 deletions assets/js/loginform_helpers.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
jQuery(document).ready(function($) {

// Helper functions for PKCE //

// Generate a secure random string using the browser crypto functions
function generateRandomString() {
var array = new Uint32Array(28);
window.crypto.getRandomValues(array);
return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');
}

// Calculate the SHA256 hash of the input text.
// Returns a promise that resolves to an ArrayBuffer
function sha256(plain) {
const encoder = new TextEncoder();
const data = encoder.encode(plain);
return window.crypto.subtle.digest('SHA-256', data);
}

// Base64-urlencodes the input string
function base64urlencode(str) {
// Convert the ArrayBuffer to string using Uint8 array to convert to what btoa accepts.
// btoa accepts chars only within ascii 0-255 and base64 encodes them.
// Then convert the base64 encoded to base64url encoded
// (replace + with -, replace / with _, trim trailing =)
return btoa(String.fromCharCode.apply(null, new Uint8Array(str)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

// Return the base64-urlencoded sha256 hash for the PKCE challenge
async function pkceChallengeFromVerifier(v) {
hashed = await sha256(v);
return base64urlencode(hashed);
}



function setPBSOAuthRememberMe() {
var rememberme = 'false';
if ( $("input[name='pbsoauth_rememberme']").prop("checked") ){
Expand All @@ -52,7 +17,7 @@ jQuery(document).ready(function($) {
});

/* Various things to do when someone clicks on a login link */
$(".passport-login-wrap li a").on("click", async function(event) {
$(".passport-login-wrap li a").on("click") {
event.preventDefault();
// set the loginprovider cookie
var logintype = $(this).closest('li').attr("class");
Expand All @@ -62,29 +27,9 @@ jQuery(document).ready(function($) {
dataLayer.push({ 'event': 'login', 'method': logintype });
}
var appended_href = $(this).attr('href');
if (logintype == 'pmsso') {
// generate and append the codeverifier but only if pmsso
console.log('setting verifier');
var code_verifier = generateRandomString();
document.cookie='pkce_code_verifier=' + code_verifier + ';domain=' + window.location.hostname + ';path=/';
var code_challenge = await pkceChallengeFromVerifier(code_verifier);
var encoded_code_challenge = encodeURIComponent(code_challenge);
appended_href = $(this).attr('href') + "&code_challenge=" + encoded_code_challenge + "&code_challenge_method=S256";
}
// send them along their way
window.location.href = appended_href;
});

// if pmsso exists, just add the pkce code challenge etc and redirect them
$(".passport-login-wrap li.pmsso a").each(async function() {
console.log('setting verifier');
var code_verifier = generateRandomString();
document.cookie='pkce_code_verifier=' + code_verifier + ';domain=' + window.location.hostname + ';path=/';
var code_challenge = await pkceChallengeFromVerifier(code_verifier);
var encoded_code_challenge = encodeURIComponent(code_challenge);
appended_href = $(this).attr('href') + "&code_challenge=" + encoded_code_challenge + "&code_challenge_method=S256";
window.location.href = appended_href;
});

});

47 changes: 47 additions & 0 deletions assets/js/pkce_loginform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
jQuery(document).ready(function($) {

// Helper functions for PKCE //

// Generate a secure random string using the browser crypto functions
function generateRandomString() {
var array = new Uint32Array(28);
window.crypto.getRandomValues(array);
return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');
}

// Calculate the SHA256 hash of the input text.
// Returns a promise that resolves to an ArrayBuffer
function sha256(plain) {
const encoder = new TextEncoder();
const data = encoder.encode(plain);
return window.crypto.subtle.digest('SHA-256', data);
}

// Base64-urlencodes the input string
function base64urlencode(str) {
// Convert the ArrayBuffer to string using Uint8 array to convert to what btoa accepts.
// btoa accepts chars only within ascii 0-255 and base64 encodes them.
// Then convert the base64 encoded to base64url encoded
// (replace + with -, replace / with _, trim trailing =)
return btoa(String.fromCharCode.apply(null, new Uint8Array(str)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

// Return the base64-urlencoded sha256 hash for the PKCE challenge
async function pkceChallengeFromVerifier(v) {
hashed = await sha256(v);
return base64urlencode(hashed);
}

// if pmsso exists, just add the pkce code challenge etc and redirect them
$(".passport-login-wrap li.pmsso a").each(async function() {
var code_verifier = generateRandomString();
document.cookie='pkce_code_verifier=' + code_verifier + ';domain=' + window.location.hostname + ';path=/';
var code_challenge = await pkceChallengeFromVerifier(code_verifier);
var encoded_code_challenge = encodeURIComponent(code_challenge);
appended_href = $(this).attr('href') + "&code_challenge=" + encoded_code_challenge + "&code_challenge_method=S256";
window.location.href = appended_href;
});

});

14 changes: 13 additions & 1 deletion classes/class-pbs-passport-authenticate.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function __construct($file) {
$this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $file ) ) );
$this->token = 'pbs_passport_authenticate';
$this->defaults = get_option($this->token);
$this->version = '0.4.1';
$this->version = '0.4.2';

// Load public-facing style sheet and JavaScript.
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
Expand All @@ -46,6 +46,7 @@ public function enqueue_scripts() {
wp_enqueue_script( 'jquery.pids' );
//only register this one, we'll enqueue it on just the loginform
wp_register_script( 'pbs_passport_loginform_js' , $this->assets_url . 'js/loginform_helpers.js', array('jquery'), $this->version, true );
wp_register_script( 'pbs_passport_pkce_js' , $this->assets_url . 'js/pkce_loginform.js', array('jquery'), $this->version, true );

//required styles
wp_enqueue_style( 'pbs_passport_css', $this->assets_url . 'css/passport_styles.css', null, $this->version);
Expand Down Expand Up @@ -184,6 +185,17 @@ public function get_laas_client($args = null){
return $laas_client;
}

public function get_pmsso_link($args = null) {
/* this generates the basic PMSSO link but does NOT generate the code challenge/verifier -- those need to be appended */
$defaults = $this->defaults;
$redirect_uri = ( !empty($args['redirect_uri']) ? $args['redirect_uri'] : site_url('pbsoauth/callback/') );
$client_id = ( !empty($args['client_id']) ? $args['client_id'] : $defaults['pmsso_client_id'] );
$customerid = ( !empty($args['customer_id']) ? $args['customer_id'] : $defaults['pmsso_customerid'] );
$prompt = ( !empty($args['prompt']) ? $args['prompt'] : 'login' );
$pmsso_url = "https://login.publicmediasignin.org/" . $customerid . "/login/authorize?client_id=" . $client_id . "&redirect_uri=" . $redirect_uri . "&scope=openid&response_type=code&prompt=" . $prompt;
return $pmsso_url;
}

public function get_pmsso_client($args = null){
$defaults = $this->defaults;
$redirect_uri = ( !empty($args['redirect_uri']) ? $args['redirect_uri'] : site_url('pbsoauth/callback/') );
Expand Down
2 changes: 1 addition & 1 deletion pbs-passport-authenticate.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/*
* Plugin Name: PBS Passport Authenticate
* Version: 0.4.0 -- Public Media SSO support
* Version: 0.4.2 -- Public Media SSO streamlined support
* Plugin URI: https://github.com/tamw-wnet/pbs-passport-authenticate
* Description: PBS Passport Authenticate
* Author: William Tam, Brian Santalone
Expand Down
9 changes: 7 additions & 2 deletions templates/loginform.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
$passport = new PBS_Passport_Authenticate(dirname(__FILE__));

$use_pmsso = isset($defaults['pmsso_is_default']) ? $defaults['pmsso_is_default'] : false;

wp_enqueue_script( 'pbs_passport_loginform_js' , $passport->assets_url . 'js/loginform_helpers.js', array('jquery'), $passport->version, true );

$links = $passport->get_oauth_links(array('scope' => 'account vppa'));
$pluginImageDir = $passport->assets_url . 'img';
$station_nice_name = $defaults['station_nice_name'];
$auth_client = false;
if ($use_pmsso) {
wp_enqueue_script( 'pbs_passport_pkce_js' , $passport->assets_url . 'js/pkce_loginform.js', array('jquery'), $passport->version, true );
$auth_client = $passport->get_pmsso_client();
$userinfo = $auth_client->check_pmsso_login();
$pmsso_url = "https://login.publicmediasignin.org/" . $defaults['pmsso_customerid'] ."/login/authorize?client_id=" . $defaults['pmsso_client_id'] . "&redirect_uri=" . site_url('pbsoauth/callback/') . "&scope=openid&prompt=login&response_type=code";
$pmsso_url = $passport->get_pmsso_link();
} else {
wp_enqueue_script( 'pbs_passport_loginform_js' , $passport->assets_url . 'js/loginform_helpers.js', array('jquery'), $passport->version, true );
$auth_client = $passport->get_laas_client();
$userinfo = $auth_client->check_pbs_login();
}
Expand All @@ -38,6 +39,10 @@
$links[$type] = $link . $statestring;
}
}
} else {
// not an activation, for PMSSO lets add a jwt state string for security
$jwt = $passport->create_jwt(array("not_member_path" => "pbsoauth/userinfo"));
$pmsso_url .= "&state=" . $jwt;
}

define('DISABLE_PLEDGE', 1);
Expand Down

0 comments on commit a4dbdc5

Please sign in to comment.