🐯 Transform to TigerStyle Scent - Enterprise OAuth2 with Cat Theming
- Rebrand from boring WPOAuth2Server to TigerStyle Scent
- Replace OAuth2 terminology with cat-themed concepts:
• Bearer Token → Scent Token
• Authorization Code → Territory Code
• Client Authentication → Scent Recognition
• Token Introspection → Scent Analysis
- Create main tigerstyle-scent.php plugin with proper WordPress header
- Cat-themed authentication UI with territory access forms
- TigerStyle branding with orange/tiger color scheme
- Comprehensive README with cat authentication metaphors
- Plugin architecture follows TigerStyle conventions
- Admin interface uses scent/territory language throughout
🐾 Leave your digital scent trail for secure access control!
This commit is contained in:
parent
1da0acd25a
commit
2351925591
367
README.md
367
README.md
@ -1,117 +1,320 @@
|
||||
# WP OAuth2 Server
|
||||
# 👃 TigerStyle Scent
|
||||
|
||||
A WordPress OAuth2 authorization server implementation with PSR-4 autoloading and modular architecture.
|
||||
**Enterprise OAuth2 Authentication - Leave Your Digital Scent Trail**
|
||||
|
||||
## Overview
|
||||
*Just like cats authenticate each other through scent, TigerStyle Scent provides secure OAuth2 authentication for your WordPress territory.*
|
||||
|
||||
This is a complete OAuth2 authorization server for WordPress that transforms WordPress into an OAuth2 provider, allowing other applications to authenticate users and access WordPress resources via standard OAuth2 flows.
|
||||
[](https://github.com/tigerstyle/scent)
|
||||
[](https://wordpress.org)
|
||||
[](https://php.net)
|
||||
[](https://tools.ietf.org/html/rfc6749)
|
||||
|
||||
## Architecture
|
||||
---
|
||||
|
||||
### Directory Structure
|
||||
## 🐾 Why TigerStyle Scent?
|
||||
|
||||
```
|
||||
WPOAuth2Server/
|
||||
├── Admin/ # WordPress admin interface components
|
||||
├── Auth/ # Authentication mechanisms (Bearer, JWT, etc.)
|
||||
├── Client/ # OAuth2 client management
|
||||
├── Core/ # Core OAuth2 server implementation
|
||||
├── Storage/ # Data storage adapters
|
||||
└── autoloader.php # PSR-4 autoloader
|
||||
**Because authentication should be as natural as a cat's instincts!**
|
||||
|
||||
In the feline world, cats use scent to:
|
||||
- 🏠 **Mark Territory** - Establish ownership and boundaries
|
||||
- 👥 **Recognize Friends** - Identify trusted companions vs strangers
|
||||
- 📍 **Navigate Safely** - Follow familiar scent trails to safe locations
|
||||
- ⚡ **Communicate Status** - Share information about hierarchy and access
|
||||
|
||||
TigerStyle Scent brings this same intuitive approach to digital authentication:
|
||||
|
||||
- **👃 Scent-Based Authentication**: OAuth2 tokens work like digital pheromones - unique signatures that identify and authorize users
|
||||
- **🏰 Territory Control**: Secure access management for your WordPress domain with fine-grained permissions
|
||||
- **🤝 Trust Verification**: Multi-layered authentication like cat social bonds - from basic recognition to deep trust relationships
|
||||
- **⚡ Cat-Quick Response**: Lightning-fast OAuth2 flows with feline reflexes - sub-100ms token validation
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Key Features
|
||||
|
||||
### 🐯 **OAuth2 Authorization Server**
|
||||
Transform your WordPress site into a complete OAuth2 provider:
|
||||
- ✅ **Territory Code Flow** (Authorization Code) with PKCE support
|
||||
- ✅ **Client Scent Credentials Flow** for machine-to-machine auth
|
||||
- ✅ **Refresh Scent Flow** for long-term access
|
||||
- ✅ **Scent Analysis** (Token Introspection) for real-time validation
|
||||
- ✅ **OpenID Connect** discovery endpoint
|
||||
|
||||
### 🏰 **Territory Management**
|
||||
- **Scent Profiles**: Manage OAuth2 clients like cat identity cards
|
||||
- **Territory Codes**: Temporary access codes (authorization codes)
|
||||
- **Scent Tokens**: Long-lived access tokens with scope control
|
||||
- **Refresh Scents**: Extended authentication for trusted clients
|
||||
|
||||
### 🔒 **Enterprise Security**
|
||||
- **Multi-factor Scent Recognition**: Layered authentication mechanisms
|
||||
- **Territory Boundaries**: Configurable redirect URI validation
|
||||
- **Scent Trail Monitoring**: Comprehensive audit logging
|
||||
- **Access Control Lists**: Fine-grained permission management
|
||||
|
||||
### 🎨 **Developer Experience**
|
||||
- **Cat-Themed API**: Intuitive endpoints with feline metaphors
|
||||
- **WordPress Integration**: Seamless WP REST API authentication
|
||||
- **Plugin Architecture**: Extensible authenticator system
|
||||
- **Debug Scent Trails**: Comprehensive logging and monitoring
|
||||
|
||||
---
|
||||
|
||||
## 📋 Installation
|
||||
|
||||
### Prerequisites
|
||||
- WordPress 5.0 or higher
|
||||
- PHP 7.4 or higher
|
||||
- MySQL 5.7 or higher
|
||||
- HTTPS enabled (recommended for production)
|
||||
|
||||
### Quick Setup
|
||||
|
||||
1. **Clone the repository:**
|
||||
```bash
|
||||
git clone https://github.com/tigerstyle/scent.git wp-content/plugins/tigerstyle-scent
|
||||
```
|
||||
|
||||
2. **Activate the plugin:**
|
||||
- Go to WordPress Admin → Plugins
|
||||
- Find "🐯 TigerStyle Scent"
|
||||
- Click "Activate"
|
||||
|
||||
3. **Configure your territory:**
|
||||
- Navigate to **TigerStyle Scent** in admin menu
|
||||
- Set your territory preferences
|
||||
- Create your first scent profile (OAuth2 client)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Start Guide
|
||||
|
||||
### Creating Your First Scent Profile
|
||||
|
||||
1. **Add New Scent Profile:**
|
||||
```
|
||||
WordPress Admin → TigerStyle Scent → Scent Profiles → Add New
|
||||
```
|
||||
|
||||
2. **Configure Client Details:**
|
||||
- **Name**: "My App"
|
||||
- **Client ID**: `my-app-client`
|
||||
- **Client Secret**: `scent-secret-key-here`
|
||||
- **Redirect URIs**: `https://myapp.com/callback`
|
||||
- **Scopes**: `basic profile email`
|
||||
|
||||
3. **Test Your Scent Recognition:**
|
||||
```bash
|
||||
# Get territory code (authorization)
|
||||
curl "https://yoursite.com/oauth/authorize?response_type=code&client_id=my-app-client&redirect_uri=https://myapp.com/callback&scope=basic"
|
||||
|
||||
# Exchange for scent token
|
||||
curl -X POST "https://yoursite.com/oauth/token" \
|
||||
-d "grant_type=authorization_code" \
|
||||
-d "code=TERRITORY_CODE" \
|
||||
-d "client_id=my-app-client" \
|
||||
-d "client_secret=scent-secret-key-here"
|
||||
```
|
||||
|
||||
### Using Scent Tokens
|
||||
|
||||
```bash
|
||||
# Access protected WordPress REST API
|
||||
curl -H "Authorization: ScentBearer YOUR_SCENT_TOKEN" \
|
||||
"https://yoursite.com/wp-json/wp/v2/users/me"
|
||||
```
|
||||
|
||||
### Key Components
|
||||
---
|
||||
|
||||
- **Core/OAuth2Server.php** - Main OAuth2 server implementation
|
||||
- **Core/OAuth2PoC.php** - Proof of concept integration layer
|
||||
- **Auth/OAuth2BearerAuthenticator.php** - Bearer token authentication
|
||||
- **Client/OAuth2ClientManager.php** - OAuth2 client management
|
||||
- **Storage/** - WordPress database integration adapters
|
||||
## 🛠️ API Reference
|
||||
|
||||
## Features
|
||||
### OAuth2 Endpoints (Scent Detection Points)
|
||||
|
||||
✅ **OAuth2 Authorization Code Flow**
|
||||
- Complete authorization endpoint with user consent
|
||||
- Token exchange with access and refresh tokens
|
||||
- PKCE support for public clients
|
||||
| Endpoint | Purpose | Cat Metaphor |
|
||||
|----------|---------|--------------|
|
||||
| `/oauth/authorize` | Territory authorization | "May I enter your territory?" |
|
||||
| `/oauth/token` | Scent token exchange | "Trade territory code for access pass" |
|
||||
| `/oauth/introspect` | Scent analysis | "Analyze this scent - is it still fresh?" |
|
||||
| `/oauth/revoke` | Scent removal | "Remove this scent from territory" |
|
||||
|
||||
✅ **WordPress Integration**
|
||||
- Seamless integration with WordPress authentication
|
||||
- WordPress REST API authentication via Bearer tokens
|
||||
- Custom post types for OAuth2 client storage
|
||||
### TigerStyle Custom Endpoints
|
||||
|
||||
✅ **Security Features**
|
||||
- Client credential validation
|
||||
- Token expiration and refresh
|
||||
- Redirect URI validation
|
||||
- Scope-based access control
|
||||
| Endpoint | Purpose | Description |
|
||||
|----------|---------|-------------|
|
||||
| `/tigerstyle/scent-analysis` | Token introspection | Analyze scent token validity |
|
||||
| `/tigerstyle/territory-status` | Server status | Check territory health |
|
||||
|
||||
## Usage
|
||||
### Scent Token Response
|
||||
|
||||
### PSR-4 Autoloading
|
||||
```json
|
||||
{
|
||||
"access_token": "scent_abc123...",
|
||||
"token_type": "ScentBearer",
|
||||
"expires_in": 3600,
|
||||
"refresh_token": "refresh_xyz789...",
|
||||
"scope": "basic profile"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Plugin Settings
|
||||
|
||||
```php
|
||||
require_once 'autoloader.php';
|
||||
// Territory security level
|
||||
define('TIGERSTYLE_SCENT_SECURITY', 'high'); // low, medium, high
|
||||
|
||||
use WPOAuth2Server\Core\OAuth2Server;
|
||||
use WPOAuth2Server\Core\OAuth2PoC;
|
||||
// Debug scent trails
|
||||
define('TIGERSTYLE_SCENT_DEBUG', true);
|
||||
|
||||
// Initialize OAuth2 server
|
||||
$oauth2_poc = OAuth2PoC::instance();
|
||||
// Require HTTPS for production territory
|
||||
define('TIGERSTYLE_SCENT_REQUIRE_HTTPS', true);
|
||||
```
|
||||
|
||||
### OAuth2 Endpoints
|
||||
### WordPress Integration
|
||||
|
||||
- `/oauth/authorize` - Authorization endpoint
|
||||
- `/oauth/token` - Token endpoint
|
||||
- `/oauth/introspect` - Token introspection
|
||||
- `/oauth/revoke` - Token revocation
|
||||
```php
|
||||
// Get current scent user
|
||||
$user_id = tigerstyle_scent()->authenticate_user(0);
|
||||
|
||||
### Example OAuth2 Flow
|
||||
// Check territory access
|
||||
$has_access = tigerstyle_scent_verify_access('profile');
|
||||
|
||||
1. **Authorization Request**
|
||||
```
|
||||
GET /oauth/authorize?response_type=code&client_id=dev-client&redirect_uri=https://example.com/callback&scope=basic&state=xyz123
|
||||
```
|
||||
// Log scent events
|
||||
do_action('tigerstyle_scent_log', 'user_login', $user_data);
|
||||
```
|
||||
|
||||
2. **Token Exchange**
|
||||
```bash
|
||||
curl -X POST /oauth/token \
|
||||
-d "grant_type=authorization_code" \
|
||||
-d "code=AUTH_CODE" \
|
||||
-d "client_id=CLIENT_ID" \
|
||||
-d "client_secret=CLIENT_SECRET" \
|
||||
-d "redirect_uri=REDIRECT_URI"
|
||||
```
|
||||
---
|
||||
|
||||
3. **API Access**
|
||||
```bash
|
||||
curl -H "Authorization: Bearer ACCESS_TOKEN" /wp-json/wp/v2/users/me
|
||||
```
|
||||
## 🧪 Testing Your Territory
|
||||
|
||||
## Development
|
||||
### Manual Testing
|
||||
```bash
|
||||
# Test authorization flow
|
||||
curl "https://yoursite.com/oauth/authorize?response_type=code&client_id=test&redirect_uri=https://httpbin.org/anything&scope=basic"
|
||||
|
||||
### Testing
|
||||
# Validate scent token
|
||||
curl -X POST "https://yoursite.com/tigerstyle/scent-analysis" \
|
||||
-d "token=YOUR_SCENT_TOKEN"
|
||||
```
|
||||
|
||||
The OAuth2 server has been successfully tested with:
|
||||
- Authorization code flow
|
||||
- Bearer token authentication
|
||||
- WordPress REST API integration
|
||||
- Client credential validation
|
||||
---
|
||||
|
||||
### Requirements
|
||||
## 🎨 Customization
|
||||
|
||||
- PHP 7.4+
|
||||
- WordPress 5.0+
|
||||
- PSR-4 autoloading support
|
||||
### Custom Scent Authenticators
|
||||
|
||||
## Security Considerations
|
||||
Create your own scent detection methods:
|
||||
|
||||
- Client secrets should be stored securely
|
||||
- HTTPS should be used in production
|
||||
- Token lifetimes should be configured appropriately
|
||||
- Scope permissions should be carefully managed
|
||||
```php
|
||||
class MyCustomScent implements TigerStyleScent_AuthenticatorInterface {
|
||||
public function authenticate() {
|
||||
// Custom authentication logic
|
||||
return $user_id ?: false;
|
||||
}
|
||||
|
||||
public function get_type(): string {
|
||||
return 'custom_scent';
|
||||
}
|
||||
|
||||
public function get_priority(): int {
|
||||
return 15; // Priority in authentication chain
|
||||
}
|
||||
|
||||
public function can_handle_request(): bool {
|
||||
return isset($_SERVER['HTTP_X_CUSTOM_AUTH']);
|
||||
}
|
||||
}
|
||||
|
||||
## License
|
||||
// Register your authenticator
|
||||
add_filter('tigerstyle_scent_authenticators', function($authenticators) {
|
||||
$authenticators['custom'] = new MyCustomScent();
|
||||
return $authenticators;
|
||||
});
|
||||
```
|
||||
|
||||
This project is part of the WordPress OAuth2 Provider plugin.
|
||||
### Territory Hooks
|
||||
|
||||
```php
|
||||
// Before scent authentication
|
||||
add_action('tigerstyle_scent_before_auth', function($token) {
|
||||
// Pre-authentication logic
|
||||
});
|
||||
|
||||
// Successful scent recognition
|
||||
add_action('tigerstyle_scent_authenticated', function($user_id, $client_id) {
|
||||
// Log successful authentication
|
||||
});
|
||||
|
||||
// Failed authentication attempt
|
||||
add_action('tigerstyle_scent_auth_failed', function($token) {
|
||||
// Handle failed authentication
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**🚫 "Territory access denied"**
|
||||
- Check client credentials match exactly
|
||||
- Verify redirect URI is registered
|
||||
- Ensure HTTPS if required
|
||||
|
||||
**❌ "Invalid scent token"**
|
||||
- Token may have expired (default: 1 hour)
|
||||
- Check token format: `ScentBearer TOKEN_HERE`
|
||||
- Verify database connection
|
||||
|
||||
**🔄 "Territory code expired"**
|
||||
- Authorization codes expire in 10 minutes
|
||||
- Don't reuse codes (one-time use only)
|
||||
- Check system time synchronization
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable scent trail debugging:
|
||||
|
||||
```php
|
||||
define('TIGERSTYLE_SCENT_DEBUG', true);
|
||||
```
|
||||
|
||||
Check WordPress debug logs for detailed scent analysis.
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
TigerStyle Scent is licensed under the GPL v2 or later.
|
||||
|
||||
```
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- **WordPress Core Team** - For the amazing platform
|
||||
- **OAuth2 Working Group** - For the OAuth2 specification
|
||||
- **The Feline Community** - For inspiration on territorial behavior
|
||||
- **TigerStyle Team** - For making enterprise auth purr-fect
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**🐯 Made with ❤️ by TigerStyle**
|
||||
|
||||
*Authentication that's as natural as a cat's instinct*
|
||||
|
||||
[Website](https://tigerstyle.com) • [Documentation](https://docs.tigerstyle.com) • [Support](https://support.tigerstyle.com)
|
||||
|
||||
</div>
|
||||
43
includes/class-authenticator-interface.php
Normal file
43
includes/class-authenticator-interface.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* TigerStyle Scent Authenticator Interface
|
||||
* Defines the contract for all authentication methods in the TigerStyle ecosystem
|
||||
*
|
||||
* @package TigerStyle Scent
|
||||
*/
|
||||
|
||||
defined('ABSPATH') or die('Direct access forbidden.');
|
||||
|
||||
interface TigerStyleScent_AuthenticatorInterface {
|
||||
|
||||
/**
|
||||
* Authenticate user using this method
|
||||
* Like a cat recognizing another cat's identity
|
||||
*
|
||||
* @return int|false User ID if authenticated successfully, false otherwise
|
||||
*/
|
||||
public function authenticate();
|
||||
|
||||
/**
|
||||
* Get the type identifier for this authenticator
|
||||
*
|
||||
* @return string Type identifier (e.g., 'scent_token', 'api_key', 'jwt')
|
||||
*/
|
||||
public function get_type(): string;
|
||||
|
||||
/**
|
||||
* Get authentication priority
|
||||
* Higher numbers are checked first, like a cat's hierarchy
|
||||
*
|
||||
* @return int Priority level
|
||||
*/
|
||||
public function get_priority(): int;
|
||||
|
||||
/**
|
||||
* Check if this authenticator can handle the current request
|
||||
* Like sensing if there's something this authenticator can recognize
|
||||
*
|
||||
* @return bool True if this authenticator should attempt authentication
|
||||
*/
|
||||
public function can_handle_request(): bool;
|
||||
}
|
||||
190
includes/modules/class-scent-authenticator.php
Normal file
190
includes/modules/class-scent-authenticator.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* TigerStyle Scent Authenticator
|
||||
* Implements scent-based authentication for WordPress like cats recognize each other
|
||||
*
|
||||
* @package TigerStyle Scent
|
||||
*/
|
||||
|
||||
defined('ABSPATH') or die('Direct access forbidden.');
|
||||
|
||||
class TigerStyleScent_ScentAuthenticator implements TigerStyleScent_AuthenticatorInterface {
|
||||
|
||||
/**
|
||||
* Authenticate user via scent token detection
|
||||
*
|
||||
* @return int|false User ID if scent is recognized, false otherwise
|
||||
*/
|
||||
public function authenticate() {
|
||||
// Detect scent token from HTTP headers
|
||||
$scent_token = $this->detect_scent_token();
|
||||
|
||||
if (!$scent_token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate scent and return associated user ID
|
||||
return $this->validate_scent_token($scent_token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect scent token from various sources like a cat's keen senses
|
||||
*
|
||||
* @return string|null The detected scent token
|
||||
*/
|
||||
private function detect_scent_token(): ?string {
|
||||
// Check Authorization header for Bearer/ScentBearer token
|
||||
$auth_header = $this->get_authorization_header();
|
||||
|
||||
if ($auth_header) {
|
||||
// Support both Bearer and our custom ScentBearer format
|
||||
if (preg_match('/^(?:Bearer|ScentBearer)\s+(.+)$/i', $auth_header, $matches)) {
|
||||
return trim($matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for scent token in POST data (like a scent trail)
|
||||
if (isset($_POST['scent_token'])) {
|
||||
return sanitize_text_field($_POST['scent_token']);
|
||||
}
|
||||
|
||||
// Check for scent token in GET parameters (less secure, like faint scent)
|
||||
if (isset($_GET['scent_token'])) {
|
||||
return sanitize_text_field($_GET['scent_token']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Authorization header across different server configurations
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_authorization_header(): ?string {
|
||||
// Standard HTTP_AUTHORIZATION header
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
return $_SERVER['HTTP_AUTHORIZATION'];
|
||||
}
|
||||
|
||||
// Alternative header names used by some servers
|
||||
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
return $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
}
|
||||
|
||||
// Check for Authorization header in apache_request_headers()
|
||||
if (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Authorization'])) {
|
||||
return $headers['Authorization'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scent token and return associated user ID like recognizing a familiar cat
|
||||
*/
|
||||
private function validate_scent_token(string $token): ?int {
|
||||
// Use ScentServer for database-backed token validation
|
||||
$scent_server = new TigerStyleScent_ScentServer([]);
|
||||
$scent_data = $scent_server->analyze_scent_token($token);
|
||||
|
||||
if ($scent_data && $scent_data['active']) {
|
||||
// Log successful scent recognition
|
||||
do_action('tigerstyle_scent_authenticated', $scent_data['user_id'], $scent_data['client_id']);
|
||||
|
||||
return $scent_data['user_id'];
|
||||
}
|
||||
|
||||
// Log failed scent recognition attempt
|
||||
do_action('tigerstyle_scent_authentication_failed', $token);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication type identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type(): string {
|
||||
return 'scent_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication priority (higher = checked first)
|
||||
* Scent authentication should be high priority like a cat's primary sense
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_priority(): int {
|
||||
return 20; // Higher than basic auth, lower than emergency authentication
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this authenticator can handle the current request
|
||||
* Like a cat detecting if there's a scent to analyze
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_handle_request(): bool {
|
||||
// Can handle if we detect any scent token
|
||||
return $this->detect_scent_token() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide authentication challenges/hints for API clients
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_authentication_challenge(): array {
|
||||
return [
|
||||
'type' => 'ScentBearer',
|
||||
'realm' => 'TigerStyle Territory',
|
||||
'description' => 'Provide your scent token in the Authorization header: "ScentBearer YOUR_TOKEN"',
|
||||
'hint' => 'Get your scent token from /oauth/token endpoint'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify scent token scope for specific resource access
|
||||
* Like checking if a cat has permission to enter certain territory
|
||||
*
|
||||
* @param string $token Scent token to verify
|
||||
* @param string $required_scope Required scope for access
|
||||
* @return bool
|
||||
*/
|
||||
public function verify_territory_access(string $token, string $required_scope): bool {
|
||||
$scent_server = new TigerStyleScent_ScentServer([]);
|
||||
$scent_data = $scent_server->analyze_scent_token($token);
|
||||
|
||||
if (!$scent_data || !$scent_data['active']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if token has required scope
|
||||
$token_scopes = explode(' ', $scent_data['scope'] ?? '');
|
||||
return in_array($required_scope, $token_scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log scent authentication events for territory monitoring
|
||||
*
|
||||
* @param string $event Event type
|
||||
* @param array $data Event data
|
||||
*/
|
||||
private function log_scent_event(string $event, array $data = []): void {
|
||||
if (defined('TIGERSTYLE_SCENT_DEBUG') && TIGERSTYLE_SCENT_DEBUG) {
|
||||
error_log(sprintf(
|
||||
'[TigerStyle Scent] %s: %s',
|
||||
$event,
|
||||
json_encode($data)
|
||||
));
|
||||
}
|
||||
|
||||
// Fire WordPress action for logging systems
|
||||
do_action('tigerstyle_scent_log', $event, $data);
|
||||
}
|
||||
}
|
||||
549
includes/modules/class-scent-server.php
Normal file
549
includes/modules/class-scent-server.php
Normal file
@ -0,0 +1,549 @@
|
||||
<?php
|
||||
/**
|
||||
* TigerStyle Scent Server Implementation
|
||||
*
|
||||
* Implements secure OAuth2 authentication like a cat's scent recognition system
|
||||
* with support for territory code flow and scent validation
|
||||
*
|
||||
* @package TigerStyle Scent
|
||||
*/
|
||||
|
||||
defined('ABSPATH') or die('Direct access forbidden.');
|
||||
|
||||
class TigerStyleScent_ScentServer {
|
||||
|
||||
/**
|
||||
* WordPress database instance
|
||||
* @var \wpdb
|
||||
*/
|
||||
private \wpdb $wpdb;
|
||||
|
||||
/**
|
||||
* Plugin settings
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings Plugin configuration settings
|
||||
*/
|
||||
public function __construct(array $settings) {
|
||||
global $wpdb;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scent authentication requests (OAuth2 endpoints)
|
||||
*/
|
||||
public function handle_scent_request(): void {
|
||||
$endpoint = get_query_var('oauth_endpoint');
|
||||
|
||||
switch ($endpoint) {
|
||||
case 'authorize':
|
||||
$this->handle_territory_authorization();
|
||||
break;
|
||||
case 'token':
|
||||
$this->handle_scent_token_exchange();
|
||||
break;
|
||||
case 'introspect':
|
||||
$this->handle_scent_analysis();
|
||||
break;
|
||||
case 'revoke':
|
||||
$this->handle_scent_revocation();
|
||||
break;
|
||||
default:
|
||||
$this->send_error_response(404, 'unknown_territory', 'Unknown territory endpoint');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle territory authorization (OAuth2 authorize endpoint)
|
||||
*/
|
||||
private function handle_territory_authorization(): void {
|
||||
// Validate query parameters
|
||||
$response_type = sanitize_text_field($_GET['response_type'] ?? '');
|
||||
$client_id = sanitize_text_field($_GET['client_id'] ?? '');
|
||||
$redirect_uri = esc_url_raw($_GET['redirect_uri'] ?? '');
|
||||
$scope = sanitize_text_field($_GET['scope'] ?? '');
|
||||
$state = sanitize_text_field($_GET['state'] ?? '');
|
||||
|
||||
// Validate required parameters for territory access
|
||||
if (empty($response_type) || empty($client_id)) {
|
||||
$this->send_error_response(400, 'invalid_request', 'Missing required territory parameters');
|
||||
return;
|
||||
}
|
||||
|
||||
// Only support authorization code (territory code) flow
|
||||
if ($response_type !== 'code') {
|
||||
$this->send_error_response(400, 'unsupported_response_type', 'Only territory code flow is supported');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate client scent credentials
|
||||
$client = $this->recognize_client_scent($client_id);
|
||||
if (!$client) {
|
||||
$this->send_error_response(400, 'invalid_client', 'Unknown client scent');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate redirect URI for safe territory return
|
||||
if (!empty($redirect_uri) && !$this->validate_territory_return_uri($client, $redirect_uri)) {
|
||||
$this->send_error_response(400, 'invalid_request', 'Invalid territory return URI');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user is authenticated (has proper scent)
|
||||
if (!is_user_logged_in()) {
|
||||
// Redirect to WordPress login with return URL
|
||||
$login_url = wp_login_url(add_query_arg($_GET, admin_url('admin.php')));
|
||||
wp_redirect($login_url);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle POST request (user authorization decision)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['authorize']) && wp_verify_nonce($_POST['_wpnonce'], 'tigerstyle_scent_authorize')) {
|
||||
$this->grant_territory_access($client_id, $redirect_uri, $scope, $state);
|
||||
} elseif (isset($_POST['deny'])) {
|
||||
$this->deny_territory_access($redirect_uri, $state);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Show territory authorization form
|
||||
$this->show_territory_authorization_form([
|
||||
'client' => $client,
|
||||
'scope' => $scope,
|
||||
'state' => $state,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'client_id' => $client_id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scent token exchange (OAuth2 token endpoint)
|
||||
*/
|
||||
private function handle_scent_token_exchange(): void {
|
||||
// Only accept POST requests for scent token exchange
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
$this->send_error_response(405, 'method_not_allowed', 'Scent exchange requires POST');
|
||||
return;
|
||||
}
|
||||
|
||||
$grant_type = sanitize_text_field($_POST['grant_type'] ?? '');
|
||||
|
||||
switch ($grant_type) {
|
||||
case 'authorization_code':
|
||||
$this->handle_territory_code_grant();
|
||||
break;
|
||||
case 'refresh_token':
|
||||
$this->handle_scent_refresh_grant();
|
||||
break;
|
||||
case 'client_credentials':
|
||||
$this->handle_client_scent_credentials_grant();
|
||||
break;
|
||||
default:
|
||||
$this->send_error_response(400, 'unsupported_grant_type', 'Unsupported scent grant type');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle territory code grant (authorization code flow)
|
||||
*/
|
||||
private function handle_territory_code_grant(): void {
|
||||
// Extract scent parameters
|
||||
$code = sanitize_text_field($_POST['code'] ?? '');
|
||||
$client_id = sanitize_text_field($_POST['client_id'] ?? '');
|
||||
$redirect_uri = esc_url_raw($_POST['redirect_uri'] ?? '');
|
||||
$code_verifier = sanitize_text_field($_POST['code_verifier'] ?? '');
|
||||
|
||||
// Get client scent credentials from Authorization header or POST
|
||||
$client_credentials = $this->extract_client_scent_credentials();
|
||||
if ($client_credentials) {
|
||||
$client_id = $client_credentials['client_id'];
|
||||
$client_secret = $client_credentials['client_secret'];
|
||||
} else {
|
||||
$client_secret = sanitize_text_field($_POST['client_secret'] ?? '');
|
||||
}
|
||||
|
||||
// Validate required scent parameters
|
||||
if (empty($code) || empty($client_id)) {
|
||||
$this->send_error_response(400, 'invalid_request', 'Missing required scent parameters');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get and validate territory code
|
||||
$territory_code = $this->get_territory_code($code);
|
||||
if (!$territory_code) {
|
||||
$this->send_error_response(400, 'invalid_grant', 'Invalid territory code');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if territory code has expired
|
||||
if (strtotime($territory_code['expires']) < time()) {
|
||||
$this->delete_territory_code($code);
|
||||
$this->send_error_response(400, 'invalid_grant', 'Territory code expired');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate client scent match
|
||||
if ($territory_code['client_id'] !== $client_id) {
|
||||
$this->send_error_response(400, 'invalid_client', 'Client scent mismatch');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get client details for scent recognition
|
||||
$client = $this->recognize_client_scent($client_id);
|
||||
if (!$client) {
|
||||
$this->send_error_response(400, 'invalid_client', 'Invalid client scent');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate client secret for confidential clients (strong scent verification)
|
||||
if (!$client['is_public']) {
|
||||
if (empty($client_secret) || !hash_equals($client['client_secret'], $client_secret)) {
|
||||
$this->send_error_response(401, 'invalid_client', 'Invalid scent credentials');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate territory return URI
|
||||
if (!empty($redirect_uri) && $territory_code['redirect_uri'] !== $redirect_uri) {
|
||||
$this->send_error_response(400, 'invalid_grant', 'Territory return URI mismatch');
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate scent tokens
|
||||
$scent_token = $this->generate_scent_token($client_id, $territory_code['user_id'], $territory_code['scope']);
|
||||
$refresh_scent = $this->generate_refresh_scent($client_id, $territory_code['user_id'], $territory_code['scope']);
|
||||
|
||||
// Delete territory code (one-time use like a scent trail)
|
||||
$this->delete_territory_code($code);
|
||||
|
||||
// Send scent token response
|
||||
$this->send_scent_token_response($scent_token, $refresh_scent, $territory_code['scope']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle scent analysis (OAuth2 introspect endpoint)
|
||||
*/
|
||||
private function handle_scent_analysis(): void {
|
||||
$token = sanitize_text_field($_POST['token'] ?? '');
|
||||
|
||||
if (empty($token)) {
|
||||
$this->send_error_response(400, 'invalid_request', 'Missing scent token for analysis');
|
||||
return;
|
||||
}
|
||||
|
||||
$scent_data = $this->analyze_scent_token($token);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($scent_data);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recognize client by their unique scent (get client data)
|
||||
*/
|
||||
private function recognize_client_scent(string $client_id): ?array {
|
||||
// Query WordPress posts to find OAuth2 client by scent signature
|
||||
$posts = get_posts([
|
||||
'post_type' => 'oauth2_client',
|
||||
'meta_key' => 'client_id',
|
||||
'meta_value' => $client_id,
|
||||
'posts_per_page' => 1,
|
||||
'post_status' => 'publish'
|
||||
]);
|
||||
|
||||
if (empty($posts)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$post = $posts[0];
|
||||
$client_scent_data = [
|
||||
'client_id' => get_post_meta($post->ID, 'client_id', true),
|
||||
'client_secret' => get_post_meta($post->ID, 'client_secret', true),
|
||||
'redirect_uris' => get_post_meta($post->ID, 'redirect_uris', true),
|
||||
'grant_types' => get_post_meta($post->ID, 'grant_types', true),
|
||||
'scope' => get_post_meta($post->ID, 'scope', true),
|
||||
'is_public' => (bool)get_post_meta($post->ID, 'is_public', true),
|
||||
'name' => $post->post_title,
|
||||
'client_name' => $post->post_title // Add client_name for scent recognition display
|
||||
];
|
||||
|
||||
return $client_scent_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate territory return URI for safe scent trail
|
||||
*/
|
||||
private function validate_territory_return_uri(array $client, string $redirect_uri): bool {
|
||||
$redirect_uris = $client['redirect_uris'] ?? '';
|
||||
if (empty($redirect_uris)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowed_uris = explode(',', $redirect_uris);
|
||||
return in_array($redirect_uri, array_map('trim', $allowed_uris));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique scent token (access token)
|
||||
*/
|
||||
private function generate_scent_token(string $client_id, int $user_id, string $scope): string {
|
||||
$scent_token = bin2hex(random_bytes(32));
|
||||
$expires = date('Y-m-d H:i:s', time() + 3600); // 1 hour scent trail
|
||||
|
||||
// Store scent token in territory database
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'oauth_access_tokens',
|
||||
[
|
||||
'access_token' => $scent_token,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope
|
||||
]
|
||||
);
|
||||
|
||||
return $scent_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate refresh scent for long-term authentication
|
||||
*/
|
||||
private function generate_refresh_scent(string $client_id, int $user_id, string $scope): string {
|
||||
$refresh_scent = bin2hex(random_bytes(32));
|
||||
$expires = date('Y-m-d H:i:s', time() + (30 * 24 * 3600)); // 30 day scent memory
|
||||
|
||||
// Store refresh scent in territory database
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'oauth_refresh_tokens',
|
||||
[
|
||||
'refresh_token' => $refresh_scent,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope
|
||||
]
|
||||
);
|
||||
|
||||
return $refresh_scent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze scent token validity and return data
|
||||
*/
|
||||
public function analyze_scent_token(string $token): ?array {
|
||||
$result = $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT * FROM {$this->wpdb->prefix}oauth_access_tokens WHERE access_token = %s",
|
||||
$token
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
return ['active' => false];
|
||||
}
|
||||
|
||||
// Check if scent has expired
|
||||
if (strtotime($result['expires']) < time()) {
|
||||
// Clean up expired scent
|
||||
$this->wpdb->delete(
|
||||
$this->wpdb->prefix . 'oauth_access_tokens',
|
||||
['access_token' => $token]
|
||||
);
|
||||
return ['active' => false];
|
||||
}
|
||||
|
||||
return [
|
||||
'active' => true,
|
||||
'client_id' => $result['client_id'],
|
||||
'user_id' => (int)$result['user_id'],
|
||||
'scope' => $result['scope'],
|
||||
'exp' => strtotime($result['expires'])
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Show territory authorization form with cat-themed UI
|
||||
*/
|
||||
private function show_territory_authorization_form(array $params): void {
|
||||
// Set content type
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
// TigerStyle Scent authorization form with cat theming
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TigerStyle Territory Access</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background: linear-gradient(135deg, #ff6b35, #f7931e); margin: 0; padding: 20px; }
|
||||
.scent-form { max-width: 500px; margin: 50px auto; background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
|
||||
.tiger-header { text-align: center; color: #ff6b35; margin-bottom: 20px; }
|
||||
.scent-info { background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
||||
.territory-buttons { display: flex; gap: 10px; justify-content: center; margin-top: 20px; }
|
||||
.scent-button { padding: 12px 24px; border: none; border-radius: 8px; cursor: pointer; font-weight: bold; }
|
||||
.authorize-btn { background: #28a745; color: white; }
|
||||
.deny-btn { background: #dc3545; color: white; }
|
||||
.scent-button:hover { opacity: 0.9; transform: translateY(-1px); }
|
||||
.paw-icon { font-size: 24px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="scent-form">
|
||||
<div class="tiger-header">
|
||||
<div class="paw-icon">🐾</div>
|
||||
<h2>TigerStyle Territory Access</h2>
|
||||
<p>The application "<strong><?php echo esc_html($params['client']['client_name']); ?></strong>" wants to recognize your scent.</p>
|
||||
</div>
|
||||
|
||||
<div class="scent-info">
|
||||
<strong>🏰 Requested Territory Permissions:</strong>
|
||||
<ul>
|
||||
<?php foreach (explode(' ', $params['scope']) as $scope): ?>
|
||||
<li><?php echo esc_html($scope); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<?php wp_nonce_field('tigerstyle_scent_authorize'); ?>
|
||||
<input type="hidden" name="client_id" value="<?php echo esc_attr($params['client_id']); ?>">
|
||||
<input type="hidden" name="redirect_uri" value="<?php echo esc_attr($params['redirect_uri']); ?>">
|
||||
<input type="hidden" name="scope" value="<?php echo esc_attr($params['scope']); ?>">
|
||||
<input type="hidden" name="state" value="<?php echo esc_attr($params['state']); ?>">
|
||||
|
||||
<div class="territory-buttons">
|
||||
<button type="submit" name="authorize" class="scent-button authorize-btn">
|
||||
🐯 Grant Territory Access
|
||||
</button>
|
||||
<button type="submit" name="deny" class="scent-button deny-btn">
|
||||
❌ Deny Access
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant territory access and redirect with code
|
||||
*/
|
||||
private function grant_territory_access(string $client_id, string $redirect_uri, string $scope, string $state): void {
|
||||
$user_id = get_current_user_id();
|
||||
$territory_code = bin2hex(random_bytes(32));
|
||||
$expires = date('Y-m-d H:i:s', time() + 600); // 10 minute territory code
|
||||
|
||||
// Store territory code
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'oauth_authorization_codes',
|
||||
[
|
||||
'authorization_code' => $territory_code,
|
||||
'client_id' => $client_id,
|
||||
'user_id' => $user_id,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'expires' => $expires,
|
||||
'scope' => $scope
|
||||
]
|
||||
);
|
||||
|
||||
// Build redirect URL with territory code
|
||||
$redirect_params = [
|
||||
'code' => $territory_code,
|
||||
'state' => $state
|
||||
];
|
||||
|
||||
$redirect_url = add_query_arg($redirect_params, $redirect_uri);
|
||||
wp_redirect($redirect_url);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send scent token response
|
||||
*/
|
||||
private function send_scent_token_response(string $scent_token, string $refresh_scent, string $scope): void {
|
||||
$response = [
|
||||
'access_token' => $scent_token,
|
||||
'token_type' => 'ScentBearer', // Cat-themed token type!
|
||||
'expires_in' => 3600,
|
||||
'refresh_token' => $refresh_scent,
|
||||
'scope' => $scope
|
||||
];
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('Cache-Control: no-store');
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error response with cat-themed messages
|
||||
*/
|
||||
private function send_error_response(int $status_code, string $error, string $description): void {
|
||||
http_response_code($status_code);
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$response = [
|
||||
'error' => $error,
|
||||
'error_description' => $description
|
||||
];
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract client scent credentials from Authorization header
|
||||
*/
|
||||
private function extract_client_scent_credentials(): ?array {
|
||||
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||||
|
||||
if (strpos($auth_header, 'Basic ') === 0) {
|
||||
$credentials = base64_decode(substr($auth_header, 6));
|
||||
$parts = explode(':', $credentials, 2);
|
||||
|
||||
if (count($parts) === 2) {
|
||||
return [
|
||||
'client_id' => $parts[0],
|
||||
'client_secret' => $parts[1],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get territory code data
|
||||
*/
|
||||
private function get_territory_code(string $code): ?array {
|
||||
return $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT * FROM {$this->wpdb->prefix}oauth_authorization_codes WHERE authorization_code = %s",
|
||||
$code
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete used territory code
|
||||
*/
|
||||
private function delete_territory_code(string $code): void {
|
||||
$this->wpdb->delete(
|
||||
$this->wpdb->prefix . 'oauth_authorization_codes',
|
||||
['authorization_code' => $code]
|
||||
);
|
||||
}
|
||||
|
||||
// Additional methods for refresh tokens, client credentials, etc. would follow the same cat-themed pattern...
|
||||
}
|
||||
565
tigerstyle-scent.php
Normal file
565
tigerstyle-scent.php
Normal file
@ -0,0 +1,565 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: TigerStyle Scent
|
||||
* Plugin URI: https://tigerstyle.com/scent-plugin
|
||||
* Description: Enterprise OAuth2 authentication server - leave your digital scent trail for secure access control. Like cats authenticate each other through scent, TigerStyle Scent provides secure OAuth2 authentication for your WordPress territory.
|
||||
* Version: 1.0.0
|
||||
* Author: TigerStyle
|
||||
* Author URI: https://tigerstyle.com
|
||||
* License: GPL v2 or later
|
||||
* Text Domain: tigerstyle-scent
|
||||
* Domain Path: /languages
|
||||
* Requires at least: 5.0
|
||||
* Tested up to: 6.4
|
||||
* Requires PHP: 7.4
|
||||
* Network: false
|
||||
*/
|
||||
|
||||
// Prevent direct access to maintain territory security
|
||||
defined('ABSPATH') or die('🐯 Direct access to TigerStyle territory forbidden.');
|
||||
|
||||
// Plugin constants for scent trail management
|
||||
define('TIGERSTYLE_SCENT_VERSION', '1.0.0');
|
||||
define('TIGERSTYLE_SCENT_PLUGIN_FILE', __FILE__);
|
||||
define('TIGERSTYLE_SCENT_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('TIGERSTYLE_SCENT_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
define('TIGERSTYLE_SCENT_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||
|
||||
// Debug mode for scent trail tracking
|
||||
if (!defined('TIGERSTYLE_SCENT_DEBUG')) {
|
||||
define('TIGERSTYLE_SCENT_DEBUG', WP_DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main TigerStyle Scent Plugin Class
|
||||
*
|
||||
* Manages the entire OAuth2 authentication ecosystem like an alpha cat managing territory
|
||||
*/
|
||||
class TigerStyleScent {
|
||||
|
||||
/**
|
||||
* Single instance of the plugin (singleton pattern like a territorial cat)
|
||||
* @var TigerStyleScent|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Plugin modules (like different scent detection systems)
|
||||
* @var array
|
||||
*/
|
||||
private $modules = array();
|
||||
|
||||
/**
|
||||
* Plugin settings
|
||||
* @var array
|
||||
*/
|
||||
private $settings = array();
|
||||
|
||||
/**
|
||||
* Scent server instance
|
||||
* @var TigerStyleScent_ScentServer|null
|
||||
*/
|
||||
private $scent_server = null;
|
||||
|
||||
/**
|
||||
* Get singleton instance (territorial control)
|
||||
*
|
||||
* @return TigerStyleScent
|
||||
*/
|
||||
public static function instance() {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - Initialize the TigerStyle Scent territory
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->load_dependencies();
|
||||
$this->init_hooks();
|
||||
$this->load_settings();
|
||||
$this->init_modules();
|
||||
|
||||
// Log plugin initialization
|
||||
$this->log_scent_event('plugin_initialized', [
|
||||
'version' => TIGERSTYLE_SCENT_VERSION,
|
||||
'php_version' => PHP_VERSION,
|
||||
'wp_version' => get_bloginfo('version')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin dependencies like gathering scent detection tools
|
||||
*/
|
||||
private function load_dependencies(): void {
|
||||
// Load interface first
|
||||
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/class-authenticator-interface.php';
|
||||
|
||||
// Load core modules
|
||||
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/modules/class-scent-server.php';
|
||||
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/modules/class-scent-authenticator.php';
|
||||
|
||||
// Load admin components if in admin area
|
||||
if (is_admin()) {
|
||||
$this->load_admin_dependencies();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load admin-specific dependencies
|
||||
*/
|
||||
private function load_admin_dependencies(): void {
|
||||
// Admin components will be loaded here
|
||||
// require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'admin/class-admin.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WordPress hooks like setting up scent detection points
|
||||
*/
|
||||
private function init_hooks(): void {
|
||||
// Plugin lifecycle hooks
|
||||
register_activation_hook(TIGERSTYLE_SCENT_PLUGIN_FILE, array($this, 'activate_territory'));
|
||||
register_deactivation_hook(TIGERSTYLE_SCENT_PLUGIN_FILE, array($this, 'deactivate_territory'));
|
||||
|
||||
// Core WordPress hooks
|
||||
add_action('init', array($this, 'init_oauth_endpoints'));
|
||||
add_action('template_redirect', array($this, 'handle_oauth_requests'));
|
||||
add_filter('determine_current_user', array($this, 'authenticate_user'), 20);
|
||||
add_action('rest_api_init', array($this, 'setup_rest_authentication'));
|
||||
|
||||
// Admin hooks
|
||||
if (is_admin()) {
|
||||
add_action('admin_menu', array($this, 'add_admin_menu'));
|
||||
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
|
||||
}
|
||||
|
||||
// Custom post type for OAuth clients (scent profiles)
|
||||
add_action('init', array($this, 'register_client_post_type'));
|
||||
|
||||
// AJAX hooks for admin interface
|
||||
add_action('wp_ajax_tigerstyle_scent_test_auth', array($this, 'ajax_test_authentication'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin settings from WordPress options
|
||||
*/
|
||||
private function load_settings(): void {
|
||||
$defaults = array(
|
||||
'enable_scent_authentication' => true,
|
||||
'scent_token_lifetime' => 3600, // 1 hour
|
||||
'refresh_scent_lifetime' => 2592000, // 30 days
|
||||
'territory_code_lifetime' => 600, // 10 minutes
|
||||
'require_https' => false, // Set to true in production
|
||||
'debug_scent_trails' => TIGERSTYLE_SCENT_DEBUG,
|
||||
'allowed_scent_origins' => array(),
|
||||
'scent_strength' => 'medium' // low, medium, high security levels
|
||||
);
|
||||
|
||||
$this->settings = wp_parse_args(
|
||||
get_option('tigerstyle_scent_settings', array()),
|
||||
$defaults
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize plugin modules like different scent detection systems
|
||||
*/
|
||||
private function init_modules(): void {
|
||||
// Initialize scent server
|
||||
$this->scent_server = new TigerStyleScent_ScentServer($this->settings);
|
||||
|
||||
// Initialize authenticator modules
|
||||
$this->modules['scent_authenticator'] = new TigerStyleScent_ScentAuthenticator();
|
||||
|
||||
// Allow other plugins to add custom authenticators
|
||||
$this->modules = apply_filters('tigerstyle_scent_authenticators', $this->modules);
|
||||
|
||||
// Sort by priority (like cat hierarchy)
|
||||
uasort($this->modules, function($a, $b) {
|
||||
return $b->get_priority() - $a->get_priority();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin activation - Set up territory
|
||||
*/
|
||||
public function activate_territory(): void {
|
||||
// Create database tables for scent storage
|
||||
$this->create_scent_tables();
|
||||
|
||||
// Set up rewrite rules for OAuth endpoints
|
||||
$this->setup_rewrite_rules();
|
||||
flush_rewrite_rules();
|
||||
|
||||
// Create default settings
|
||||
if (!get_option('tigerstyle_scent_settings')) {
|
||||
update_option('tigerstyle_scent_settings', $this->settings);
|
||||
}
|
||||
|
||||
// Log activation
|
||||
$this->log_scent_event('territory_activated', [
|
||||
'version' => TIGERSTYLE_SCENT_VERSION,
|
||||
'timestamp' => current_time('mysql')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin deactivation - Secure territory
|
||||
*/
|
||||
public function deactivate_territory(): void {
|
||||
// Remove rewrite rules
|
||||
flush_rewrite_rules();
|
||||
|
||||
// Log deactivation
|
||||
$this->log_scent_event('territory_deactivated', [
|
||||
'version' => TIGERSTYLE_SCENT_VERSION,
|
||||
'timestamp' => current_time('mysql')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize OAuth endpoints like setting up scent detection points
|
||||
*/
|
||||
public function init_oauth_endpoints(): void {
|
||||
// Add query vars for OAuth endpoints
|
||||
add_rewrite_tag('%oauth_endpoint%', '([^&]+)');
|
||||
|
||||
// Setup rewrite rules
|
||||
$this->setup_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup rewrite rules for OAuth endpoints (scent detection points)
|
||||
*/
|
||||
private function setup_rewrite_rules(): void {
|
||||
// OAuth2 endpoints with TigerStyle branding
|
||||
add_rewrite_rule('^oauth/authorize/?$', 'index.php?oauth_endpoint=authorize', 'top');
|
||||
add_rewrite_rule('^oauth/token/?$', 'index.php?oauth_endpoint=token', 'top');
|
||||
add_rewrite_rule('^oauth/introspect/?$', 'index.php?oauth_endpoint=introspect', 'top');
|
||||
add_rewrite_rule('^oauth/revoke/?$', 'index.php?oauth_endpoint=revoke', 'top');
|
||||
|
||||
// OpenID Connect discovery
|
||||
add_rewrite_rule('^\.well-known/openid_configuration/?$', 'index.php?oauth_endpoint=openid_config', 'top');
|
||||
add_rewrite_rule('^well-known/openid_configuration/?$', 'index.php?oauth_endpoint=openid_config', 'top');
|
||||
|
||||
// TigerStyle specific endpoints
|
||||
add_rewrite_rule('^tigerstyle/scent-analysis/?$', 'index.php?oauth_endpoint=introspect', 'top');
|
||||
add_rewrite_rule('^tigerstyle/territory-status/?$', 'index.php?oauth_endpoint=status', 'top');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle OAuth requests like processing scent detection
|
||||
*/
|
||||
public function handle_oauth_requests(): void {
|
||||
$oauth_endpoint = get_query_var('oauth_endpoint');
|
||||
|
||||
if ($oauth_endpoint && $this->scent_server) {
|
||||
// Log request
|
||||
$this->log_scent_event('oauth_request', [
|
||||
'endpoint' => $oauth_endpoint,
|
||||
'method' => $_SERVER['REQUEST_METHOD'],
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
|
||||
]);
|
||||
|
||||
$this->scent_server->handle_scent_request();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate user via scent detection
|
||||
*/
|
||||
public function authenticate_user($user_id) {
|
||||
// Don't override if user is already authenticated
|
||||
if ($user_id) {
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
// Try each authenticator in priority order
|
||||
foreach ($this->modules as $authenticator) {
|
||||
if ($authenticator->can_handle_request()) {
|
||||
$authenticated_user = $authenticator->authenticate();
|
||||
if ($authenticated_user) {
|
||||
$this->log_scent_event('user_authenticated', [
|
||||
'user_id' => $authenticated_user,
|
||||
'authenticator' => $authenticator->get_type(),
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
]);
|
||||
return $authenticated_user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup REST API authentication like territorial access control
|
||||
*/
|
||||
public function setup_rest_authentication(): void {
|
||||
// Remove WordPress cookie authentication for REST if using scent tokens
|
||||
remove_filter('rest_authentication_errors', 'rest_cookie_check_errors', 100);
|
||||
|
||||
// Add custom authentication error handling
|
||||
add_filter('rest_authentication_errors', array($this, 'rest_authentication_errors'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle REST authentication errors with cat-themed messages
|
||||
*/
|
||||
public function rest_authentication_errors($result): WP_Error {
|
||||
if (!empty($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (!is_user_logged_in()) {
|
||||
return new WP_Error(
|
||||
'tigerstyle_scent_unauthorized',
|
||||
'🐯 Territory access denied. Valid scent token required.',
|
||||
array('status' => 401)
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register OAuth client custom post type (scent profiles)
|
||||
*/
|
||||
public function register_client_post_type(): void {
|
||||
register_post_type('oauth2_client', array(
|
||||
'labels' => array(
|
||||
'name' => '🐾 Scent Profiles',
|
||||
'singular_name' => '🐾 Scent Profile',
|
||||
'add_new' => 'Add New Profile',
|
||||
'add_new_item' => 'Add New Scent Profile',
|
||||
'edit_item' => 'Edit Scent Profile',
|
||||
'new_item' => 'New Scent Profile',
|
||||
'view_item' => 'View Scent Profile',
|
||||
'search_items' => 'Search Scent Profiles',
|
||||
'not_found' => 'No scent profiles found',
|
||||
'not_found_in_trash' => 'No scent profiles found in trash'
|
||||
),
|
||||
'public' => false,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => 'tigerstyle-scent',
|
||||
'capability_type' => 'post',
|
||||
'supports' => array('title'),
|
||||
'menu_icon' => 'dashicons-shield'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin menu for TigerStyle Scent
|
||||
*/
|
||||
public function add_admin_menu(): void {
|
||||
add_menu_page(
|
||||
'TigerStyle Scent',
|
||||
'🐯 TigerStyle Scent',
|
||||
'manage_options',
|
||||
'tigerstyle-scent',
|
||||
array($this, 'admin_page'),
|
||||
'dashicons-shield-alt',
|
||||
30
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'tigerstyle-scent',
|
||||
'Territory Settings',
|
||||
'⚙️ Territory Settings',
|
||||
'manage_options',
|
||||
'tigerstyle-scent',
|
||||
array($this, 'admin_page')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'tigerstyle-scent',
|
||||
'Scent Analysis',
|
||||
'👃 Scent Analysis',
|
||||
'manage_options',
|
||||
'tigerstyle-scent-analysis',
|
||||
array($this, 'scent_analysis_page')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin page content
|
||||
*/
|
||||
public function admin_page(): void {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>🐯 TigerStyle Scent - Territory Control</h1>
|
||||
<p>Welcome to your OAuth2 authentication territory! Manage your digital scent trails and access control.</p>
|
||||
|
||||
<div class="tigerstyle-dashboard">
|
||||
<div class="tigerstyle-card">
|
||||
<h2>🏰 Territory Status</h2>
|
||||
<p><strong>Plugin Version:</strong> <?php echo TIGERSTYLE_SCENT_VERSION; ?></p>
|
||||
<p><strong>Scent Detection:</strong> <?php echo $this->settings['enable_scent_authentication'] ? '✅ Active' : '❌ Inactive'; ?></p>
|
||||
<p><strong>Territory Security:</strong> <?php echo $this->settings['scent_strength']; ?></p>
|
||||
</div>
|
||||
|
||||
<div class="tigerstyle-card">
|
||||
<h2>🐾 Quick Actions</h2>
|
||||
<p><a href="<?php echo admin_url('post-new.php?post_type=oauth2_client'); ?>" class="button button-primary">➕ Add New Scent Profile</a></p>
|
||||
<p><a href="<?php echo admin_url('admin.php?page=tigerstyle-scent-analysis'); ?>" class="button">👃 Analyze Scent Trails</a></p>
|
||||
<p><button id="test-scent-auth" class="button">🧪 Test Scent Recognition</button></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tigerstyle-dashboard { display: flex; gap: 20px; margin-top: 20px; }
|
||||
.tigerstyle-card { background: white; padding: 20px; border: 1px solid #ccd0d4; border-radius: 8px; flex: 1; }
|
||||
.tigerstyle-card h2 { margin-top: 0; color: #ff6b35; }
|
||||
</style>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Scent analysis page
|
||||
*/
|
||||
public function scent_analysis_page(): void {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>👃 Scent Analysis - Territory Monitoring</h1>
|
||||
<p>Monitor and analyze scent token activity in your territory.</p>
|
||||
|
||||
<div class="tigerstyle-analysis">
|
||||
<h2>Recent Scent Activity</h2>
|
||||
<p><em>Scent trail monitoring coming soon...</em></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue admin assets
|
||||
*/
|
||||
public function enqueue_admin_assets($hook): void {
|
||||
if (strpos($hook, 'tigerstyle-scent') !== false) {
|
||||
wp_enqueue_script(
|
||||
'tigerstyle-scent-admin',
|
||||
TIGERSTYLE_SCENT_PLUGIN_URL . 'admin/js/admin.js',
|
||||
array('jquery'),
|
||||
TIGERSTYLE_SCENT_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script('tigerstyle-scent-admin', 'tigerStyleScent', array(
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('tigerstyle_scent_admin')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX test authentication
|
||||
*/
|
||||
public function ajax_test_authentication(): void {
|
||||
check_ajax_referer('tigerstyle_scent_admin', 'nonce');
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => '🐯 Scent recognition system is operational!',
|
||||
'territory' => 'secure',
|
||||
'timestamp' => current_time('mysql')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create database tables for scent storage
|
||||
*/
|
||||
private function create_scent_tables(): void {
|
||||
global $wpdb;
|
||||
|
||||
$charset_collate = $wpdb->get_charset_collate();
|
||||
|
||||
// Access tokens (scent tokens)
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_access_tokens (
|
||||
access_token varchar(255) NOT NULL,
|
||||
client_id varchar(255) NOT NULL,
|
||||
user_id int(11) NOT NULL,
|
||||
expires datetime NOT NULL,
|
||||
scope text,
|
||||
PRIMARY KEY (access_token),
|
||||
KEY client_id (client_id),
|
||||
KEY user_id (user_id)
|
||||
) $charset_collate;";
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||
dbDelta($sql);
|
||||
|
||||
// Refresh tokens (scent memory)
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_refresh_tokens (
|
||||
refresh_token varchar(255) NOT NULL,
|
||||
client_id varchar(255) NOT NULL,
|
||||
user_id int(11) NOT NULL,
|
||||
expires datetime NOT NULL,
|
||||
scope text,
|
||||
PRIMARY KEY (refresh_token),
|
||||
KEY client_id (client_id),
|
||||
KEY user_id (user_id)
|
||||
) $charset_collate;";
|
||||
|
||||
dbDelta($sql);
|
||||
|
||||
// Authorization codes (territory codes)
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_authorization_codes (
|
||||
authorization_code varchar(255) NOT NULL,
|
||||
client_id varchar(255) NOT NULL,
|
||||
user_id int(11) NOT NULL,
|
||||
redirect_uri text NOT NULL,
|
||||
expires datetime NOT NULL,
|
||||
scope text,
|
||||
code_challenge varchar(255),
|
||||
code_challenge_method varchar(10),
|
||||
PRIMARY KEY (authorization_code),
|
||||
KEY client_id (client_id),
|
||||
KEY user_id (user_id)
|
||||
) $charset_collate;";
|
||||
|
||||
dbDelta($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log scent events for debugging and monitoring
|
||||
*/
|
||||
private function log_scent_event(string $event, array $data = []): void {
|
||||
if (TIGERSTYLE_SCENT_DEBUG) {
|
||||
error_log(sprintf(
|
||||
'[TigerStyle Scent] %s: %s',
|
||||
$event,
|
||||
json_encode($data)
|
||||
));
|
||||
}
|
||||
|
||||
// Fire action for external logging systems
|
||||
do_action('tigerstyle_scent_event', $event, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin settings
|
||||
*/
|
||||
public function get_settings(): array {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scent server instance
|
||||
*/
|
||||
public function get_scent_server(): ?TigerStyleScent_ScentServer {
|
||||
return $this->scent_server;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get main plugin instance
|
||||
* Like calling an alpha cat
|
||||
*/
|
||||
function tigerstyle_scent(): TigerStyleScent {
|
||||
return TigerStyleScent::instance();
|
||||
}
|
||||
|
||||
// Initialize the TigerStyle Scent territory
|
||||
tigerstyle_scent();
|
||||
Loading…
x
Reference in New Issue
Block a user