/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // set req and res object internally $this->request = $request; $this->response = $response; // get server context to local var $serverContext = $this->getServerContext(); // Get the authentications locally so we do not mess with inter-request configuration $authenticationSets = array(); // check if there are some volatile rewrite map definitions so add them if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS)) { $authenticationSets[] = $requestContext->getModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS); } // get the global authentications last, as volatile authentications are prefered here as more specific configurations can lessen security $authenticationSets[] = $this->authentications; // get system logger $systemLogger = $serverContext->getLogger(LoggerUtils::SYSTEM); // check authentication information if something matches foreach ($authenticationSets as $authenticationSet) { foreach ($authenticationSet as $uriPattern => $data) { // check if pattern matches uri if (preg_match('/' . $uriPattern . '/', $requestContext->getServerVar(ServerVars::X_REQUEST_URI))) { // set type Instance to local ref $typeInstance = $this->getAuthenticationInstance($uriPattern, $data); // check if auth header is not set in coming request headers if (!$request->hasHeader(Protocol::HEADER_AUTHORIZATION)) { // send header for challenge authentication against client $response->addHeader(Protocol::HEADER_WWW_AUTHENTICATE, $typeInstance->getAuthenticateHeader()); // throw exception for auth required throw new ModuleException(null, 401); } // init type instance by request $typeInstance->init($request->getHeader(Protocol::HEADER_AUTHORIZATION), $request->getMethod()); try { // check if auth works if ($typeInstance->authenticate()) { // set server vars $requestContext->setServerVar(ServerVars::REMOTE_USER, $typeInstance->getUsername()); // break out because everything is fine at this point break; } } catch (\Exception $e) { // log exception as warning to not end up with a 500 response which is not wanted here $systemLogger->warning($e->getMessage()); } // send header for challenge authentication against client $response->addHeader(Protocol::HEADER_WWW_AUTHENTICATE, $typeInstance->getAuthenticateHeader()); // throw exception for auth required throw new ModuleException(null, 401); } } } }
/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // get server context to local ref $serverContext = $this->getServerContext(); // check if response post is is comming if (ModuleHooks::RESPONSE_POST === $hook) { $this->checkShouldDisconnect(); return; } // if wrong hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } try { // init upstreamname and transport $upstreamName = null; $transport = 'tcp'; // check if we've configured module variables if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_FILE_HANDLER_VARIABLES)) { // load the volatile file handler variables and set connection data $fileHandlerVariables = $requestContext->getModuleVar(ModuleVars::VOLATILE_FILE_HANDLER_VARIABLES); // check if upstream is set for proxy function if (isset($fileHandlerVariables['upstream'])) { $upstreamName = $fileHandlerVariables['upstream']; } if (isset($fileHandlerVariables['transport'])) { $transport = $fileHandlerVariables['transport']; } } // if there was no upstream defined if (is_null($upstreamName)) { throw new ModuleException('No upstream configured for proxy filehandler'); } // get upstream instance by configured upstream name $upstream = $serverContext->getUpstream($upstreamName); // find next proxy server by given upstream type $remoteAddr = $requestContext->getServerVar(ServerVars::REMOTE_ADDR); $proxyServer = $upstream->findServer(md5($remoteAddr)); // build proxy socket address for connection $proxySocketAddress = sprintf('%s://%s:%s', $transport, $proxyServer->getAddress(), $proxyServer->getPort()); // check if should reconnect $this->checkShouldDisconnect(); // check if proxy connection object was initialised but connection resource is not ready if ($this->connection && $this->connection->getStatus() === false) { // unset connection if corrupt $this->connection = null; } // check if connection should be established if ($this->connection === null) { // create and connect to defined backend $this->connection = StreamSocket::getClientInstance($proxySocketAddress); // set proxy connection resource as stream source for body stream directly // that avoids huge memory consumtion when transferring big files via proxy connections $response->setBodyStream($this->connection->getConnectionResource()); } // get connection to local var $connection = $this->connection; // build up raw request start line $rawRequestString = sprintf('%s %s %s' . "\r\n", $request->getMethod(), $request->getUri(), HttpProtocol::VERSION_1_1); // populate request headers $headers = $request->getHeaders(); foreach ($headers as $headerName => $headerValue) { // @todo: make keep-alive available for proxy connections if ($headerName === HttpProtocol::HEADER_CONNECTION) { $headerValue = HttpProtocol::HEADER_CONNECTION_VALUE_CLOSE; } $rawRequestString .= $headerName . HttpProtocol::HEADER_SEPARATOR . $headerValue . "\r\n"; } // get current protocol $reqProto = $requestContext->getServerVar(ServerVars::REQUEST_SCHEME); // add proxy depending headers $rawRequestString .= HttpProtocol::HEADER_X_FORWARD_FOR . HttpProtocol::HEADER_SEPARATOR . $remoteAddr . "\r\n"; $rawRequestString .= HttpProtocol::HEADER_X_FORWARDED_PROTO . HttpProtocol::HEADER_SEPARATOR . $reqProto . "\r\n"; $rawRequestString .= "\r\n"; // write headers to proxy connection $connection->write($rawRequestString); // copy raw request body stream to proxy connection $connection->copyStream($request->getBodyStream()); // read status line from proxy connection $statusLine = $connection->readLine(1024, 5); // parse start line list(, $responseStatusCode) = explode(' ', $statusLine); // map everything from proxy response to our response object $response->setStatusCode($responseStatusCode); $line = ''; $messageHeaders = ''; while (!in_array($line, array("\r\n", "\n"))) { // read next line $line = $connection->readLine(); // enhance headers $messageHeaders .= $line; } // remove ending CRLF's before parsing $messageHeaders = trim($messageHeaders); // check if headers are empty if (strlen($messageHeaders) === 0) { throw new HttpException('Missing headers'); } // delimit headers by CRLF $headerLines = explode("\r\n", $messageHeaders); // iterate all headers foreach ($headerLines as $headerLine) { // extract header info $extractedHeaderInfo = explode(HttpProtocol::HEADER_SEPARATOR, trim($headerLine)); if (!$extractedHeaderInfo || $extractedHeaderInfo[0] === $headerLine) { throw new HttpException('Wrong header format'); } // split name and value list($headerName, $headerValue) = $extractedHeaderInfo; // check header name for server // @todo: make this configurable if ($headerName === HttpProtocol::HEADER_SERVER) { continue; } // add header $response->addHeader(trim($headerName), trim($headerValue)); } // set flag false by default $this->shouldDisconnect = false; // check if connection should be closed as given in connection header if ($response->getHeader(HttpProtocol::HEADER_CONNECTION) === HttpProtocol::HEADER_CONNECTION_VALUE_CLOSE) { $this->shouldDisconnect = true; } } catch (\AppserverIo\Psr\Socket\SocketReadException $e) { // close and unset connection and try to process the request again to // not let a white page get delivered to the client $this->shouldDisconnect = true; return $this->process($request, $response, $requestContext, $hook); } catch (\AppserverIo\Psr\Socket\SocketReadTimeoutException $e) { // close and unset connection and try to process the request again to // not let a white page get delivered to the client $this->shouldDisconnect = true; return $this->process($request, $response, $requestContext, $hook); } // set response to be dispatched at this point $response->setState(HttpResponseStates::DISPATCH); }
/** * Initialize by the authentication type with the data from the request. * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request The request with the content of authentication data sent by client * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response The response sent back to the client * * @return void * @throws \AppserverIo\Http\Authentication\AuthenticationException If the authentication type can't be initialized */ public function init(RequestInterface $request, ResponseInterface $response) { // set vars internally $this->reqMethod = $request->getMethod(); // parse auth data $this->parse($request, $response); }