diff --git a/app/controllers/app_controller.php b/app/controllers/app_controller.php index f3059e20..a3cd31c8 100755 --- a/app/controllers/app_controller.php +++ b/app/controllers/app_controller.php @@ -8,23 +8,34 @@ class AppController extends Controller { var $uses = array('User'); var $helpers = array('Javascript', 'Time', 'Html', 'Form'); + + // Define public actions that don't require authentication + var $allowedActions = array(); + function beforeFilter() { + + // Check if current action is allowed without authentication + if (in_array($this->action, $this->allowedActions)) { + error_log('[AUTH_BYPASS] Action ' . $this->action . ' allowed without authentication'); + return; + } $user = null; // Check if Tailscale authentication is enabled if (Configure::read('Tailscale.enabled')) { - error_log('[TAILSCALE_AUTH] Checking Tailscale authentication headers'); - error_log($_SERVER); - // Check for Tailscale authentication headers - $tailscaleLogin = isset($_SERVER['HTTP_TAILSCALE_USER_LOGIN']) ? $_SERVER['HTTP_TAILSCALE_USER_LOGIN'] : null; - $tailscaleName = isset($_SERVER['HTTP_TAILSCALE_USER_NAME']) ? $_SERVER['HTTP_TAILSCALE_USER_NAME'] : null; + error_log('[WEBAUTH] Checking web authentication headers'); + error_log('X-Webauth-User: ' . (isset($_SERVER['HTTP_X_WEBAUTH_USER']) ? $_SERVER['HTTP_X_WEBAUTH_USER'] : 'not set')); + error_log('X-Webauth-Name: ' . (isset($_SERVER['HTTP_X_WEBAUTH_NAME']) ? $_SERVER['HTTP_X_WEBAUTH_NAME'] : 'not set')); + // Check for web authentication headers + $tailscaleLogin = isset($_SERVER['HTTP_X_WEBAUTH_USER']) ? $_SERVER['HTTP_X_WEBAUTH_USER'] : null; + $tailscaleName = isset($_SERVER['HTTP_X_WEBAUTH_NAME']) ? $_SERVER['HTTP_X_WEBAUTH_NAME'] : null; if ($tailscaleLogin) { - // Log Tailscale authentication attempt - error_log('[TAILSCALE_AUTH] Attempting authentication for: ' . $tailscaleLogin); + // Log web authentication attempt + error_log('[WEBAUTH] Attempting authentication for: ' . $tailscaleLogin); - // Try to find user by email address from Tailscale header + // Try to find user by email address from web auth header $user = $this->User->find('first', array( 'recursive' => 0, 'conditions' => array('User.email' => $tailscaleLogin) @@ -62,9 +73,9 @@ class AppController extends Controller { 'recursive' => 0, 'conditions' => array('User.id' => $this->User->id) )); - error_log('[TAILSCALE_AUTH] Created new user: ' . $tailscaleLogin); + error_log('[WEBAUTH] Created new user: ' . $tailscaleLogin); } else { - error_log('[TAILSCALE_AUTH] Failed to create user: ' . $tailscaleLogin); + error_log('[WEBAUTH] Failed to create user: ' . $tailscaleLogin); } } } @@ -83,6 +94,27 @@ class AppController extends Controller { error_log('[AUTH_SUCCESS] User authenticated: ' . $user['User']['email']); } else { error_log('[AUTH_FAILED] No valid authentication found'); + + // Check if we have any authentication attempt (Web Auth or Basic Auth) + $hasAuthAttempt = (Configure::read('Tailscale.enabled') && isset($_SERVER['HTTP_X_WEBAUTH_USER'])) || + isset($_SERVER["PHP_AUTH_USER"]); + + // If there was an authentication attempt but it failed, return 401 + if ($hasAuthAttempt) { + header('HTTP/1.1 401 Unauthorized'); + header('Content-Type: text/plain'); + echo "Authentication failed. Invalid credentials or user not found."; + error_log('[AUTH_FAILED] Returning 401 Unauthorized'); + exit(); + } + + // If no authentication headers at all, request authentication + header('WWW-Authenticate: Basic realm="CMC Sales System"'); + header('HTTP/1.1 401 Unauthorized'); + header('Content-Type: text/plain'); + echo "Authentication required. Please provide valid credentials."; + error_log('[AUTH_FAILED] No authentication headers, requesting authentication'); + exit(); } $this->set("currentuser", $user); @@ -129,10 +161,10 @@ class AppController extends Controller { // Check if Tailscale authentication is enabled if (Configure::read('Tailscale.enabled')) { - $tailscaleLogin = isset($_SERVER['HTTP_TAILSCALE_USER_LOGIN']) ? $_SERVER['HTTP_TAILSCALE_USER_LOGIN'] : null; + $tailscaleLogin = isset($_SERVER['HTTP_X_WEBAUTH_USER']) ? $_SERVER['HTTP_X_WEBAUTH_USER'] : null; if ($tailscaleLogin) { - // Try to find user by email address from Tailscale header + // Try to find user by email address from web auth header $user = $this->User->find('first', array( 'recursive' => 0, 'conditions' => array('User.email' => $tailscaleLogin) diff --git a/deploy-production.sh b/deploy-production.sh new file mode 100755 index 00000000..8908f04c --- /dev/null +++ b/deploy-production.sh @@ -0,0 +1,203 @@ +#!/bin/bash + +# Production Deployment Script for CMC Sales +# This script deploys the application to sales.cmctechnologies.com.au +# Based on .gitlab-ci.yml deployment steps + +set -e # Exit on error + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +PRODUCTION_HOST="cmc@sales.cmctechnologies.com.au" +PRODUCTION_DIR="/home/cmc/cmc-sales" +CURRENT_BRANCH=$(git branch --show-current) + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}CMC Sales Production Deployment Script${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" + +# Check if we're on master branch +if [ "$CURRENT_BRANCH" != "master" ]; then + echo -e "${YELLOW}Warning: You are not on the master branch.${NC}" + echo -e "${YELLOW}Current branch: $CURRENT_BRANCH${NC}" + read -p "Do you want to continue deployment from $CURRENT_BRANCH? (y/N): " confirm + if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then + echo -e "${RED}Deployment cancelled.${NC}" + exit 1 + fi +fi + +# Check for uncommitted changes +if ! git diff-index --quiet HEAD --; then + echo -e "${YELLOW}Warning: You have uncommitted changes.${NC}" + git status --short + read -p "Do you want to continue? (y/N): " confirm + if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then + echo -e "${RED}Deployment cancelled.${NC}" + exit 1 + fi +fi + +# Get latest commit hash for build arg +COMMIT_HASH=$(git rev-parse --short HEAD) +echo -e "${GREEN}Deploying commit: $COMMIT_HASH${NC}" +echo "" + +# Push latest changes to origin +echo -e "${YELLOW}Step 1: Pushing latest changes to origin...${NC}" +git push origin $CURRENT_BRANCH +if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ Changes pushed successfully${NC}" +else + echo -e "${RED}✗ Failed to push changes${NC}" + exit 1 +fi +echo "" + +# SSH to production and execute deployment +echo -e "${YELLOW}Step 2: Connecting to production server...${NC}" +echo -e "${YELLOW}Executing deployment on $PRODUCTION_HOST${NC}" +echo "" + +ssh -T $PRODUCTION_HOST << 'ENDSSH' +set -e + +# Color codes for remote output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${GREEN}Connected to production server${NC}" +echo "" + +# Navigate to project directory +echo -e "${YELLOW}Step 3: Navigating to project directory...${NC}" +cd /home/cmc/cmc-sales +pwd +echo "" + +# Pull latest changes +echo -e "${YELLOW}Step 4: Pulling latest changes from Git...${NC}" +git pull origin master +if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ Git pull successful${NC}" +else + echo -e "${RED}✗ Git pull failed${NC}" + exit 1 +fi +echo "" + +# Get commit hash for build +COMMIT_HASH=$(git rev-parse --short HEAD) +echo -e "${GREEN}Building from commit: $COMMIT_HASH${NC}" + +# Copy userpasswd file +echo -e "${YELLOW}Step 5: Copying userpasswd file...${NC}" +cp /home/cmc/cmc-sales/userpasswd /home/cmc/userpasswd +if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ userpasswd file copied${NC}" +else + echo -e "${RED}✗ Failed to copy userpasswd file${NC}" + exit 1 +fi +echo "" + +# Build Docker image +echo -e "${YELLOW}Step 6: Building Docker image...${NC}" +docker build --build-arg=COMMIT=$COMMIT_HASH . -t "cmc:latest" +if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ Docker image built successfully${NC}" +else + echo -e "${RED}✗ Docker build failed${NC}" + exit 1 +fi +echo "" + +# Stop existing container +echo -e "${YELLOW}Step 7: Stopping existing container...${NC}" +export ID=$(docker ps -q --filter ancestor=cmc:latest) +if [ ! -z "$ID" ]; then + docker kill $ID + echo -e "${GREEN}✓ Existing container stopped${NC}" + sleep 1 +else + echo -e "${YELLOW}No existing container found${NC}" +fi +echo "" + +# Run new container +echo -e "${YELLOW}Step 8: Starting new container...${NC}" +docker run -d --restart always -p 127.0.0.1:8888:80 \ + --mount type=bind,source=/mnt/vault/pdf,target=/var/www/cmc-sales/app/webroot/pdf \ + --mount type=bind,source=/mnt/vault/attachments_files,target=/var/www/cmc-sales/app/webroot/attachments_files \ + --mount type=bind,source=/mnt/vault/emails,target=/var/www/emails \ + --mount type=bind,source=/mnt/vault/vaultmsgs,target=/var/www/vaultmsgs \ + cmc:latest + +if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ New container started successfully${NC}" +else + echo -e "${RED}✗ Failed to start new container${NC}" + exit 1 +fi +echo "" + +# Verify container is running +echo -e "${YELLOW}Step 9: Verifying deployment...${NC}" +sleep 2 +NEW_ID=$(docker ps -q --filter ancestor=cmc:latest) +if [ ! -z "$NEW_ID" ]; then + echo -e "${GREEN}✓ Container is running with ID: $NEW_ID${NC}" + docker ps --filter ancestor=cmc:latest --format "table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" +else + echo -e "${RED}✗ Container is not running!${NC}" + exit 1 +fi +echo "" + +# Show recent logs +echo -e "${YELLOW}Step 10: Recent container logs:${NC}" +docker logs --tail 20 $NEW_ID +echo "" + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}✓ Deployment completed successfully!${NC}" +echo -e "${GREEN}========================================${NC}" + +ENDSSH + +if [ $? -eq 0 ]; then + echo "" + echo -e "${GREEN}========================================${NC}" + echo -e "${GREEN}✓ Production deployment successful!${NC}" + echo -e "${GREEN}========================================${NC}" + echo "" + echo -e "${GREEN}Application is running at:${NC}" + echo -e "${GREEN} Internal: http://127.0.0.1:8888${NC}" + echo -e "${GREEN} External: https://sales.cmctechnologies.com.au${NC}" + echo "" + echo -e "${YELLOW}To view live logs:${NC}" + echo " ssh $PRODUCTION_HOST 'docker logs -f \$(docker ps -q --filter ancestor=cmc:latest)'" + echo "" + echo -e "${YELLOW}To rollback if needed:${NC}" + echo " ssh $PRODUCTION_HOST 'docker run -d --restart always -p 127.0.0.1:8888:80 [previous-image-id]'" +else + echo "" + echo -e "${RED}========================================${NC}" + echo -e "${RED}✗ Deployment failed!${NC}" + echo -e "${RED}========================================${NC}" + echo "" + echo -e "${YELLOW}To check the status:${NC}" + echo " ssh $PRODUCTION_HOST 'docker ps -a'" + echo "" + echo -e "${YELLOW}To view logs:${NC}" + echo " ssh $PRODUCTION_HOST 'docker logs \$(docker ps -aq | head -1)'" + exit 1 +fi \ No newline at end of file