454 lines
16 KiB
PHP
454 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Plugin Name: Baron SSO Integration
|
|
* Description: Integrates WordPress with Baron SSO for authentication via popup.
|
|
* Version: 1.2.0
|
|
* Author: Gemini
|
|
* License: GPL-2.0-or-later
|
|
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
|
* Text Domain: baron-sso
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly.
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Add custom CSS to the head for the fixed login/logout button.
|
|
*/
|
|
function sso_custom_styles() {
|
|
echo '<style>
|
|
/* 5. General Layout & Typography */
|
|
body {
|
|
font-size: 17px;
|
|
line-height: 1.7;
|
|
color: #333;
|
|
}
|
|
.sso-container {
|
|
max-width: 1040px;
|
|
margin: 0 auto;
|
|
padding: 0 24px;
|
|
}
|
|
/* Adjusting the main content area if a theme uses this common class */
|
|
.site-content {
|
|
max-width: 1040px;
|
|
margin: 0 auto;
|
|
padding: 0 24px;
|
|
}
|
|
/* Remove extra top margin from the first section title after the hero */
|
|
.entry-header + h2,
|
|
.entry-header + .widget-title {
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* 1. Hero Header Section */
|
|
.entry-header {
|
|
position: relative;
|
|
padding: 72px 24px 56px;
|
|
/* Negative margin to break out of a constrained container and go full-width */
|
|
margin-left: calc(50% - 50vw);
|
|
margin-right: calc(50% - 50vw);
|
|
margin-bottom: 48px;
|
|
background: linear-gradient(145deg, #1a2a3a, #3a4a5a); /* Dark blue-gray gradient */
|
|
color: #fff;
|
|
text-align: center;
|
|
}
|
|
|
|
/* Clean up spacing if the header is inside the main content area */
|
|
.site-content .entry-header {
|
|
margin-top: 0;
|
|
}
|
|
body.home .entry-header {
|
|
margin-top: -20px; /* Adjust as needed for specific themes */
|
|
}
|
|
|
|
.page-title, .entry-title {
|
|
margin: 0;
|
|
font-size: clamp(44px, 5vw, 64px) !important;
|
|
letter-spacing: -0.02em;
|
|
color: #6868AC !important; /* Custom page title color */
|
|
text-align: center;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.page-title::after, .entry-title::after {
|
|
content: "This page demonstrates a seamless single sign-on integration for WordPress.";
|
|
display: block;
|
|
margin-top: 12px;
|
|
text-align: center;
|
|
opacity: 0.9;
|
|
font-size: 16px;
|
|
font-weight: normal;
|
|
letter-spacing: normal;
|
|
color: #fff; /* Ensure subtitle stays white */
|
|
}
|
|
|
|
/* 4. Section Title Divider */
|
|
h2, .widget-title {
|
|
font-size: 2.5rem;
|
|
margin-top: 64px;
|
|
margin-bottom: 32px;
|
|
padding-bottom: 16px;
|
|
border-bottom: 2px solid #eee;
|
|
}
|
|
|
|
/* 2. Login Status Badge & Button Container */
|
|
#sso-fixed-button {
|
|
position: fixed;
|
|
top: 10px;
|
|
right: 15px;
|
|
z-index: 99999;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
body.admin-bar #sso-fixed-button {
|
|
top: 42px;
|
|
}
|
|
|
|
.sso-status-badge {
|
|
display: inline-block;
|
|
padding: 6px 10px;
|
|
background-color: rgba(0,0,0,0.1);
|
|
color: #333;
|
|
border-radius: 5px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
}
|
|
body.admin-bar .sso-status-badge {
|
|
background-color: rgba(255,255,255,0.8);
|
|
}
|
|
|
|
/* 6. Product-style Button */
|
|
#sso-fixed-button a {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
height: 42px;
|
|
padding: 0 14px;
|
|
background-color: #A19FE7; /* Custom button color */
|
|
color: #fff !important;
|
|
border: 1px solid rgba(0,0,0,0.1);
|
|
border-radius: 6px;
|
|
text-decoration: none !important;
|
|
font-weight: bold;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
transition: transform 0.15s ease, filter 0.15s ease, box-shadow 0.15s ease;
|
|
}
|
|
#sso-fixed-button a:hover {
|
|
transform: translateY(-2px);
|
|
filter: brightness(1.1);
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
|
}
|
|
#sso-fixed-button a:active {
|
|
transform: translateY(0);
|
|
filter: brightness(1.0);
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
/* 3. Post Card Styling */
|
|
.post, .article {
|
|
background-color: #ffffff;
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 8px;
|
|
padding: 24px;
|
|
margin-bottom: 24px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
transition: box-shadow 0.3s ease, transform 0.3s ease;
|
|
}
|
|
.post:hover, .article:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 7px 14px rgba(0,0,0,0.07);
|
|
}
|
|
|
|
.post .entry-title, .article .entry-title {
|
|
font-size: 24px !important;
|
|
margin-bottom: 12px;
|
|
color: #1a2a3a !important;
|
|
}
|
|
.post .entry-summary, .post .entry-content,
|
|
.article .entry-summary, .article .entry-content {
|
|
font-size: 16px;
|
|
color: #555;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
/* Remove the old divider */
|
|
.post + .post, .article + .article {
|
|
border-top: none;
|
|
padding-top: 24px;
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* 7. Call-to-Action Banner */
|
|
.sso-cta-banner {
|
|
background-color: #f0f7ff;
|
|
border: 1px solid #b3d7ff;
|
|
border-radius: 6px;
|
|
padding: 20px 24px;
|
|
margin-bottom: 48px;
|
|
text-align: center;
|
|
color: #004085;
|
|
}
|
|
.sso-cta-banner p {
|
|
margin: 0;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
}
|
|
</style>';
|
|
}
|
|
add_action( 'wp_head', 'sso_custom_styles' );
|
|
|
|
|
|
// =============================================================================
|
|
// 2. PUBLIC-FACING FEATURES (LOGIN/LOGOUT BUTTON)
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Injects a fixed login/logout button at the top of the body.
|
|
*/
|
|
function sso_inject_header_button() {
|
|
// Don't show on admin pages or the login page itself.
|
|
if ( is_admin() || $GLOBALS['pagenow'] === 'wp-login.php' ) {
|
|
return;
|
|
}
|
|
|
|
echo '<div id="sso-fixed-button">';
|
|
if ( is_user_logged_in() ) {
|
|
$current_user = wp_get_current_user();
|
|
echo '<span class="sso-status-badge">Logged in as: ' . esc_html( $current_user->user_email ) . '</span>';
|
|
echo '<a href="' . wp_logout_url( home_url() ) . '">Logout</a>';
|
|
} else {
|
|
$sso_frontend_url = get_option( 'sso_plugin_frontend_url' );
|
|
if ( ! empty( $sso_frontend_url ) ) {
|
|
// Construct the redirect URL for SSO to return to WordPress after login.
|
|
$redirect_after_sso = ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
|
$login_url = add_query_arg( 'redirect_url', urlencode( $redirect_after_sso ), $sso_frontend_url );
|
|
// Now, the button opens a popup window.
|
|
echo '<a href="#" onclick="openSsoPopup(\'' . esc_url( $login_url ) . '\'); return false;">Baron SSO Login</a>';
|
|
}
|
|
}
|
|
echo '</div>';
|
|
}
|
|
add_action( 'wp_body_open', 'sso_inject_header_button' );
|
|
|
|
|
|
/**
|
|
* Injects a Call-to-Action banner before the main content loop.
|
|
*/
|
|
function sso_add_cta_banner() {
|
|
// Show only on the main blog/posts page and when the user is not logged in.
|
|
if ( is_home() && ! is_user_logged_in() ) {
|
|
echo '<div class="sso-cta-banner">
|
|
<p>SSO로 로그인하면 회원 전용 글을 확인할 수 있습니다.</p>
|
|
</div>';
|
|
}
|
|
}
|
|
add_action( 'loop_start', 'sso_add_cta_banner' );
|
|
|
|
|
|
/**
|
|
* Adds the JavaScript for the SSO popup to the footer.
|
|
*/
|
|
function sso_add_popup_script() {
|
|
?>
|
|
<script>
|
|
function openSsoPopup(url) {
|
|
var width = 600, height = 700;
|
|
var left = (screen.width / 2) - (width / 2);
|
|
var top = (screen.height / 2) - (height / 2);
|
|
var popup = window.open(url, 'ssoLoginPopup', 'width=' + width + ',height=' + height + ',top=' + top + ',left=' + left);
|
|
}
|
|
|
|
// Listen for a message from the popup.
|
|
window.addEventListener('message', function(event) {
|
|
// For security, you should validate the origin here.
|
|
// Example: if (event.origin !== "https://sso.hmac.kr") return;
|
|
|
|
// Check if the received data is an object with the expected structure.
|
|
if (typeof event.data === 'object' && event.data !== null && event.data.type === 'LOGIN_SUCCESS' && event.data.token) {
|
|
console.log('SSO login success message object received. Processing token...');
|
|
|
|
// Construct the URL to reload the page with the token.
|
|
// This will trigger the PHP handler on the backend.
|
|
const currentUrl = new URL(window.location.href);
|
|
currentUrl.searchParams.set('token', event.data.token);
|
|
|
|
// Redirect to the new URL to process the login.
|
|
window.location.href = currentUrl.toString();
|
|
|
|
} else {
|
|
// This log can be removed in production.
|
|
console.log('Received message, but data format is not the expected SSO login success object.', event.data);
|
|
}
|
|
}, false);
|
|
</script>
|
|
<?php
|
|
}
|
|
add_action( 'wp_footer', 'sso_add_popup_script' );
|
|
|
|
|
|
// =============================================================================
|
|
// 3. SSO CALLBACK AND LOGIN PROCESSING
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Handles the JWT from the SSO provider when the main page is reloaded with a token.
|
|
*/
|
|
function sso_handle_jwt_login() {
|
|
// This now runs on the main page, not the popup.
|
|
if ( ! is_user_logged_in() && isset( $_GET['token'] ) ) {
|
|
|
|
$jwt = sanitize_text_field( $_GET['token'] );
|
|
|
|
// Process the JWT, create/find the user, and set the auth cookie.
|
|
sso_process_jwt_and_login( $jwt );
|
|
|
|
// After processing, redirect to the same URL without the token to clean up the address bar.
|
|
wp_redirect( remove_query_arg( 'token' ) );
|
|
exit;
|
|
}
|
|
}
|
|
add_action( 'init', 'sso_handle_jwt_login' );
|
|
|
|
|
|
/**
|
|
* Core function to process JWT, find/create a user, and log them in.
|
|
*/
|
|
function sso_process_jwt_and_login( $jwt ) {
|
|
// --- JWT Validation Logic ---
|
|
// IMPORTANT: THIS IS A NON-SECURE PLACEHOLDER. Replace with proper validation.
|
|
$jwt_parts = explode('.', $jwt);
|
|
if (count($jwt_parts) !== 3) {
|
|
wp_die('SSO Error: Invalid token format.');
|
|
return;
|
|
}
|
|
$payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $jwt_parts[1])));
|
|
|
|
// --- DEBUGGING: Print the payload and stop ---
|
|
// echo '<pre>';
|
|
// print_r($payload);
|
|
// echo '</pre>';
|
|
// wp_die('JWT Payload Inspection. Check the subject field name.');
|
|
// --- END DEBUGGING ---
|
|
|
|
if ( ! isset( $payload->sub ) || empty( $payload->sub ) ) {
|
|
wp_die('SSO Error: User subject ID (sub) not found or is empty in token.');
|
|
return;
|
|
}
|
|
$sso_user_id = sanitize_text_field($payload->sub);
|
|
// --- End of Placeholder ---
|
|
|
|
// Find user by SSO subject ID meta field.
|
|
$users = get_users([
|
|
'meta_key' => 'sso_subject_id',
|
|
'meta_value' => $sso_user_id,
|
|
'number' => 1,
|
|
'count_total' => false
|
|
]);
|
|
|
|
$user = ! empty( $users ) ? $users[0] : null;
|
|
|
|
if ( ! $user ) {
|
|
// User does not exist, so create them.
|
|
// Use the SSO ID for the username, ensuring it's unique.
|
|
$username = sanitize_user( $sso_user_id );
|
|
$base_username = $username;
|
|
$i = 1;
|
|
while ( username_exists( $username ) ) {
|
|
$username = $base_username . $i++;
|
|
}
|
|
|
|
// Create a fake email, as it's required by WordPress but not by our SSO.
|
|
$user_email = $username . '@sso.local';
|
|
|
|
$user_id = wp_create_user( $username, wp_generate_password(), $user_email );
|
|
|
|
if ( is_wp_error( $user_id ) ) {
|
|
wp_die('Error creating SSO user: ' . $user_id->get_error_message());
|
|
}
|
|
|
|
// Store the SSO user ID for future lookups.
|
|
update_user_meta( $user_id, 'sso_subject_id', $sso_user_id );
|
|
|
|
$user = get_user_by( 'id', $user_id );
|
|
}
|
|
|
|
// Log the user in.
|
|
if ( $user ) {
|
|
wp_set_current_user( $user->ID );
|
|
wp_set_auth_cookie( $user->ID, true );
|
|
do_action( 'wp_login', $user->user_login, $user );
|
|
}
|
|
}
|
|
|
|
|
|
// =============================================================================
|
|
// 4. CONTENT ACCESS RESTRICTIONS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Redirects unauthenticated users from single posts to the SSO login page.
|
|
*/
|
|
function sso_restrict_single_posts() {
|
|
if ( is_single() && ! is_user_logged_in() ) {
|
|
$sso_frontend_url = get_option( 'sso_plugin_frontend_url' );
|
|
if ( ! empty( $sso_frontend_url ) ) {
|
|
$current_url = ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
|
// The redirect URL for SSO is now a dedicated popup callback URL
|
|
$sso_callback_url = add_query_arg( 'sso_popup_callback', '1', $current_url );
|
|
$login_url = add_query_arg( 'redirect_url', urlencode( $sso_callback_url ), $sso_frontend_url );
|
|
wp_redirect( esc_url( $login_url ) );
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
// Let's disable this for now to simplify testing the popup button first.
|
|
// add_action( 'template_redirect', 'sso_restrict_single_posts' );
|
|
|
|
|
|
// =============================================================================
|
|
// 5. ADMIN SETTINGS PAGE
|
|
// =============================================================================
|
|
|
|
function sso_plugin_add_settings_page() {
|
|
add_options_page('Baron SSO Settings', 'Baron SSO Login', 'manage_options', 'baron-sso-settings', 'sso_plugin_render_settings_page');
|
|
}
|
|
add_action( 'admin_menu', 'sso_plugin_add_settings_page' );
|
|
|
|
function sso_plugin_render_settings_page() {
|
|
?>
|
|
<div class="wrap">
|
|
<h1>Baron SSO Login Settings</h1>
|
|
<form action="options.php" method="post">
|
|
<?php
|
|
settings_fields( 'sso_plugin_options' );
|
|
do_settings_sections( 'sso_plugin_settings' );
|
|
?>
|
|
<table class="form-table">
|
|
<tr valign="top">
|
|
<th scope="row">Baron SSO Frontend URL</th>
|
|
<td>
|
|
<input type="text" name="sso_plugin_frontend_url"
|
|
value="<?php echo esc_attr( get_option( 'sso_plugin_frontend_url' ) ); ?>"
|
|
size="50" placeholder="Enter the Baron SSO Frontend Login URL" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<?php submit_button( 'Save Settings' ); ?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
function sso_plugin_register_settings() {
|
|
register_setting('sso_plugin_options', 'sso_plugin_frontend_url', [
|
|
'type' => 'string',
|
|
'sanitize_callback' => 'esc_url_raw',
|
|
'default' => '',
|
|
]);
|
|
add_settings_section('sso_plugin_main_section', 'Main Settings', null, 'sso_plugin_settings');
|
|
}
|
|
add_action( 'admin_init', 'sso_plugin_register_settings' );
|