A Laravel package for seamless integration with Central Authentication Service (CAS) servers. This package provides secure single sign-on authentication with JWT tokens, signature validation, and role-based access control.
- 🔐 Secure SSO Authentication - JWT token-based authentication
- 🛡️ Signature Validation - HMAC SHA-256 request signing
- 👥 Role-Based Access Control - Middleware for role protection
- 🔧 Easy Configuration - Environment-based setup
- 📝 Comprehensive Logging - Authentication event tracking
- ⚡ Performance Optimized - Token caching and validation
- 🎯 Laravel Integration - Native Laravel guards and middleware
composer require insol-dev/central-authentication-serverphp artisan vendor:publish --tag=cas-client-configAdd the following to your .env file:
# CAS Server Configuration
CAS_SERVER_URL=http://localhost:5000
CAS_CLIENT_ID=your_client_id
CAS_CLIENT_USERNAME=your_client_username
CAS_CLIENT_PASSWORD=your_client_password
# Security Settings
CAS_SIGNATURE_SECRET=your-256-bit-signature-secret
CAS_ENABLE_SIGNATURE_VALIDATION=true
# Callback Configuration
CAS_CALLBACK_URL=http://yourapp.com/cas/callback// In routes/web.php
use CasSystem\LaravelClient\Middleware\CasAuthentication;
use CasSystem\LaravelClient\Middleware\CasRole;
Route::middleware([CasAuthentication::class])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/profile', [ProfileController::class, 'show']);
});
// Protect with specific roles
Route::middleware([CasAuthentication::class, CasRole::class . ':admin,manager'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});use CasSystem\LaravelClient\Facades\CasClient;
class AuthController extends Controller
{
public function login(Request $request)
{
$returnUrl = $request->query('return_url', route('dashboard'));
$loginUrl = CasClient::getLoginUrl($returnUrl);
return redirect($loginUrl);
}
public function callback(Request $request)
{
$token = $request->query('token');
if (!$token) {
return redirect()->route('login')->with('error', 'No authentication token provided');
}
$user = CasClient::validateToken($token);
if ($user) {
// Store user data in session
session([
'cas_user' => $user,
'cas_token' => $token,
'authenticated' => true
]);
return redirect()->route('dashboard')->with('success', 'Login successful');
}
return redirect()->route('login')->with('error', 'Authentication failed');
}
public function logout(Request $request)
{
$token = session('cas_token');
// Logout from CAS server
CasClient::logout($token);
// Clear local session
session()->forget(['cas_user', 'cas_token', 'authenticated']);
session()->invalidate();
session()->regenerateToken();
return redirect('/')->with('success', 'Logged out successfully');
}
}// In your controllers
public function dashboard(Request $request)
{
$user = session('cas_user');
$username = $user['username'];
$email = $user['email'];
$roles = $user['roles'] ?? [];
return view('dashboard', compact('user', 'username', 'email', 'roles'));
}
// Check user roles
use CasSystem\LaravelClient\Facades\CasClient;
if (CasClient::userHasRole($user, 'admin')) {
// User has admin role
}
if (CasClient::userHasAnyRole($user, ['admin', 'manager'])) {
// User has admin OR manager role
}
if (CasClient::userHasAllRoles($user, ['user', 'verified'])) {
// User has BOTH user AND verified roles
}{{-- In your Blade templates --}}
@if(session('authenticated'))
<div class="user-info">
<h3>Welcome, {{ session('cas_user.name') }}</h3>
<p>Email: {{ session('cas_user.email') }}</p>
<p>Roles: {{ implode(', ', session('cas_user.roles', [])) }}</p>
</div>
<form method="POST" action="{{ route('cas.logout') }}">
@csrf
<button type="submit" class="btn btn-danger">Logout</button>
</form>
@else
<a href="{{ route('cas.login') }}" class="btn btn-primary">Login with CAS</a>
@endif# Required Settings
CAS_SERVER_URL=http://localhost:5000 # CAS server URL
CAS_CLIENT_ID=your_client_id # Your registered client ID
CAS_CLIENT_USERNAME=your_client_username # Client authentication username
CAS_CLIENT_PASSWORD=your_client_password # Client authentication password
# Security Settings
CAS_SIGNATURE_SECRET=your-256-bit-secret # HMAC signature secret
CAS_ENABLE_SIGNATURE_VALIDATION=true # Enable request signing
# Callback Configuration
CAS_CALLBACK_URL=http://yourapp.com/cas/callback # Where CAS redirects after login
# Optional Settings
CAS_TIMEOUT=30 # HTTP request timeout
CAS_VERIFY_SSL=true # Verify SSL certificates
CAS_CACHE_ENABLED=true # Enable user data caching
CAS_CACHE_TTL=3600 # Cache time-to-live (seconds)
CAS_LOGGING_ENABLED=true # Enable authentication loggingEdit config/cas-client.php for advanced options:
return [
// User management
'user' => [
'create_local_users' => true,
'model' => App\Models\User::class,
'field_mapping' => [
'username' => 'username',
'email' => 'email',
'name' => 'name',
],
],
// Route configuration
'routes' => [
'enabled' => true,
'prefix' => 'cas',
'middleware' => ['web'],
],
// Logging configuration
'logging' => [
'enabled' => true,
'channel' => 'single',
'level' => 'info',
],
];Protects routes requiring CAS authentication:
Route::middleware(['cas.auth'])->group(function () {
Route::get('/protected', [Controller::class, 'method']);
});Protects routes requiring specific roles:
// Single role
Route::middleware(['cas.auth', 'cas.role:admin'])->group(function () {
Route::get('/admin', [AdminController::class, 'index']);
});
// Multiple roles (user needs ANY of these roles)
Route::middleware(['cas.auth', 'cas.role:admin,manager,supervisor'])->group(function () {
Route::get('/management', [ManagementController::class, 'index']);
});// Get CAS login URL
$loginUrl = CasClient::getLoginUrl($returnUrl);
// Validate authentication token
$user = CasClient::validateToken($token);
// Get cached user data
$user = CasClient::getUserFromToken($token);
// Logout from CAS server
$success = CasClient::logout($token);
// Role checking methods
$hasRole = CasClient::userHasRole($user, 'admin');
$hasAnyRole = CasClient::userHasAnyRole($user, ['admin', 'manager']);
$hasAllRoles = CasClient::userHasAllRoles($user, ['user', 'verified']);$user = [
'id' => 1,
'username' => 'john_doe',
'email' => 'john@example.com',
'name' => 'John Doe',
'roles' => ['user', 'manager'],
// Additional fields from CAS server
];When enabled, all requests to the CAS server are signed with HMAC SHA-256:
// Automatic signature generation
$signature = hash_hmac('sha256', $payload, $secret);The payload includes:
- HTTP method
- Request URI
- Request body
- Timestamp
- Client ID
User data is cached to reduce CAS server load:
// Cached for performance
Cache::put("cas_user_{$token}", $userData, $ttl);Comprehensive error handling for all CAS operations:
try {
$user = CasClient::validateToken($token);
} catch (CasAuthException $e) {
Log::error('CAS authentication failed', ['error' => $e->getMessage()]);
}-
Authentication Loop
- Check
CAS_CALLBACK_URLmatches your route - Verify session configuration
- Ensure middleware order is correct
- Check
-
Token Validation Fails
- Verify client credentials in CAS server
- Check
CAS_SIGNATURE_SECRETif using signatures - Ensure CAS server is accessible
-
Role Access Denied
- Verify user has required roles in CAS
- Check role middleware configuration
- Ensure roles are properly synced
Enable debug logging:
CAS_LOGGING_ENABLED=true
CAS_LOG_LEVEL=debugTest your configuration:
# Test CAS server connectivity
curl -I http://your-cas-server.com/health
# Test token validation
php artisan tinker
>>> app(CasAuthService::class)->validateToken('your-test-token');This package is open-sourced software licensed under the MIT license.
For support, visit innovativesolution.com.np or create an issue on GitHub.
Please see CONTRIBUTING.md for details on how to contribute to this package.
Please see CHANGELOG.md for details on recent changes.