|
1 | 1 | <?php
|
2 | 2 |
|
3 | 3 | class MethodExecutionException extends Exception {}
|
| 4 | +class CommandExecutionException extends Exception {} |
4 | 5 |
|
5 |
| -// Include the nusoap library |
| 6 | +// Include the nusoap library and required constants |
6 | 7 | require_once './lib/nusoap.php';
|
| 8 | +require_once '../includes/ws-constants.php'; |
| 9 | +require_once '../includes/ws-authenticate-jwt-token.php'; |
7 | 10 |
|
8 | 11 | $lServerName = $_SERVER['SERVER_NAME'];
|
9 | 12 |
|
@@ -37,86 +40,124 @@ class MethodExecutionException extends Exception {}
|
37 | 40 | '',
|
38 | 41 | array(
|
39 | 42 | 'message' => array('name' => 'message', 'type' => 'xsd:string'),
|
| 43 | + 'command' => array('name' => 'command', 'type' => 'xsd:string'), |
40 | 44 | 'securityLevel' => array('name' => 'securityLevel', 'type' => 'xsd:string'),
|
41 | 45 | 'timestamp' => array('name' => 'timestamp', 'type' => 'xsd:string'),
|
42 | 46 | 'output' => array('name' => 'output', 'type' => 'xsd:string')
|
43 | 47 | )
|
44 | 48 | );
|
45 | 49 |
|
46 |
| -// Define the "echoMessage" method |
| 50 | +/** |
| 51 | + * Function: authenticateRequest |
| 52 | + * Handles request authentication and CORS headers. |
| 53 | + * |
| 54 | + * @param int $lSecurityLevel The security level. |
| 55 | + * @throws InvalidTokenException If the authentication fails. |
| 56 | + */ |
| 57 | +function authenticateRequest($lSecurityLevel) { |
| 58 | + |
| 59 | + // Set CORS headers |
| 60 | + header(CORS_ACCESS_CONTROL_ALLOW_ORIGIN); |
| 61 | + header('Access-Control-Allow-Methods: POST, OPTIONS'); // Allowed methods |
| 62 | + header('Access-Control-Allow-Headers: Content-Type, Authorization'); // Specify allowed headers |
| 63 | + header('Access-Control-Expose-Headers: Authorization'); // Expose headers if needed |
| 64 | + header(CONTENT_TYPE_XML); // Set content type as XML |
| 65 | + |
| 66 | + // Handle preflight requests (OPTIONS) |
| 67 | + if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { |
| 68 | + header(CORS_ACCESS_CONTROL_MAX_AGE); // Cache the preflight response for 600 seconds (10 minutes) |
| 69 | + http_response_code(RESPONSE_CODE_NO_CONTENT); // No Content |
| 70 | + exit(); |
| 71 | + } |
| 72 | + |
| 73 | + // Allow only POST requests |
| 74 | + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { |
| 75 | + http_response_code(RESPONSE_CODE_METHOD_NOT_ALLOWED); |
| 76 | + header(CONTENT_TYPE_XML); |
| 77 | + echo ERROR_MESSAGE_METHOD_NOT_ALLOWED; |
| 78 | + exit(); |
| 79 | + } |
| 80 | + |
| 81 | + // Authenticate the user if required |
| 82 | + if ($lSecurityLevel >= SECURITY_LEVEL_MEDIUM) { |
| 83 | + try { |
| 84 | + $lDecodedToken = authenticateJWTToken(); // Authenticate using the shared function |
| 85 | + } catch (InvalidTokenException $e) { |
| 86 | + http_response_code(RESPONSE_CODE_UNAUTHORIZED); |
| 87 | + header(CONTENT_TYPE_XML); |
| 88 | + echo ERROR_MESSAGE_UNAUTHORIZED_PREFIX . 'Unauthorized: ' . htmlspecialchars($e->getMessage()) . ERROR_MESSAGE_UNAUTHORIZED_SUFFIX; |
| 89 | + exit(); |
| 90 | + } |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +/** |
| 95 | + * Define the "echoMessage" method |
| 96 | + * |
| 97 | + * @param string $pMessage The message to echo. |
| 98 | + * @return array An associative array containing the echoed message and metadata. |
| 99 | + * @throws MethodExecutionException If there is an error executing the method. |
| 100 | + */ |
47 | 101 | function echoMessage($pMessage) {
|
48 | 102 |
|
49 |
| - try{ |
| 103 | + try { |
50 | 104 | // Include required constants and utility classes
|
51 | 105 | require_once '../../includes/constants.php';
|
52 | 106 | require_once '../../classes/EncodingHandler.php';
|
53 | 107 | require_once '../../classes/SQLQueryHandler.php';
|
54 | 108 |
|
55 | 109 | $SQLQueryHandler = new SQLQueryHandler(0);
|
56 |
| - |
57 | 110 | $lSecurityLevel = $SQLQueryHandler->getSecurityLevelFromDB();
|
58 |
| - |
59 | 111 | $Encoder = new EncodingHandler();
|
60 | 112 |
|
61 |
| - switch ($lSecurityLevel){ |
62 |
| - default: // Default case: This code is insecure |
63 |
| - case "0": // This code is insecure |
64 |
| - case "1": // This code is insecure |
65 |
| - $lProtectAgainstCommandInjection=false; |
66 |
| - $lProtectAgainstXSS = false; |
67 |
| - break; |
68 |
| - |
69 |
| - case "2": |
70 |
| - case "3": |
71 |
| - case "4": |
72 |
| - case "5": // This code is fairly secure |
73 |
| - $lProtectAgainstCommandInjection=true; |
74 |
| - $lProtectAgainstXSS = true; |
75 |
| - break; |
76 |
| - }// end switch |
77 |
| - |
| 113 | + // Authenticate the request using the shared function |
| 114 | + authenticateRequest($lSecurityLevel); |
| 115 | + |
| 116 | + // Set security-related variables |
| 117 | + $lProtectAgainstCommandInjection = $lSecurityLevel >= SECURITY_LEVEL_MEDIUM; |
| 118 | + $lProtectAgainstXSS = $lSecurityLevel >= SECURITY_LEVEL_MEDIUM; |
| 119 | + |
78 | 120 | // Apply XSS protection if enabled
|
79 |
| - if ($lProtectAgainstXSS) { |
80 |
| - $lMessage = $Encoder->encodeForHTML($pMessage); |
81 |
| - } else { |
82 |
| - $lMessage = $pMessage; |
83 |
| - } |
| 121 | + $lMessage = $lProtectAgainstXSS ? $Encoder->encodeForHTML($pMessage) : $pMessage; |
| 122 | + |
| 123 | + // Construct the command |
| 124 | + $lCommand = $lProtectAgainstCommandInjection |
| 125 | + ? escapeshellcmd("echo " . escapeshellarg($lMessage)) |
| 126 | + : "echo $lMessage"; |
84 | 127 |
|
85 |
| - // Handle command execution based on the protection flag |
86 |
| - if ($lProtectAgainstCommandInjection) { |
87 |
| - $lResult = $lMessage; |
88 |
| - } else { |
89 |
| - // Allow command injection vulnerability (insecure) |
90 |
| - $lResult = shell_exec("echo " . $lMessage); |
| 128 | + // Execute the command and capture output |
| 129 | + $lOutput = shell_exec($lCommand); |
| 130 | + if ($lOutput === null) { |
| 131 | + throw new CommandExecutionException("Command execution failed."); |
91 | 132 | }
|
92 | 133 |
|
93 | 134 | // Get the current timestamp
|
94 |
| - $lTimestamp = date('Y-m-d H:i:s'); |
| 135 | + $lTimestamp = date(DATE_TIME_FORMAT); |
95 | 136 |
|
96 | 137 | // Create a structured response as an associative array
|
97 | 138 | $lResponse = array(
|
98 | 139 | 'message' => $lMessage,
|
| 140 | + 'command' => $lCommand, |
99 | 141 | 'securityLevel' => $lSecurityLevel,
|
100 | 142 | 'timestamp' => $lTimestamp,
|
101 |
| - 'output' => $lResult |
| 143 | + 'output' => $lOutput |
102 | 144 | );
|
103 | 145 |
|
104 | 146 | return $lResponse; // Return as an array for NuSOAP to serialize
|
105 | 147 |
|
106 |
| - }catch(Exception $e){ |
107 |
| - $lMessage = "Error executing method echoMessage in webservice ws-echo.php"; |
| 148 | + } catch (Exception $e) { |
| 149 | + $lMessage = "Error executing method echoMessage in webservice ws-echo.php: " . $e->getMessage(); |
108 | 150 | throw new MethodExecutionException($lMessage);
|
109 |
| - }// end try |
110 |
| - |
111 |
| -} // end function echoMessage |
| 151 | + } |
| 152 | +} |
112 | 153 |
|
113 | 154 | // Handle the SOAP request with error handling
|
114 | 155 | try {
|
115 | 156 | // Process the incoming SOAP request
|
116 | 157 | $lSOAPWebService->service(file_get_contents("php://input"));
|
117 | 158 | } catch (Exception $e) {
|
118 | 159 | // Send a fault response back to the client
|
119 |
| - $lSOAPWebService->fault('Server', "SOAP Service Error: " . $e->getMessage()); |
| 160 | + $lSOAPWebService->fault('Server', "SOAP Service Error: " . htmlspecialchars($e->getMessage())); |
120 | 161 | }
|
121 | 162 |
|
122 | 163 | ?>
|
0 commit comments