aboutsummaryrefslogtreecommitdiffstats
path: root/library/oauth2/src/OAuth2/Response.php
diff options
context:
space:
mode:
authorzotlabs <mike@macgirvin.com>2016-10-07 14:11:24 -0700
committerzotlabs <mike@macgirvin.com>2016-10-07 14:11:24 -0700
commit10863a5949cc59771424cb809af5c9f279f78a58 (patch)
tree7a86223b830c1ae784bd4557bbefee9f60169542 /library/oauth2/src/OAuth2/Response.php
parentbf02e0428347350126abdd1726aa3e58c9ed63bb (diff)
downloadvolse-hubzilla-10863a5949cc59771424cb809af5c9f279f78a58.tar.gz
volse-hubzilla-10863a5949cc59771424cb809af5c9f279f78a58.tar.bz2
volse-hubzilla-10863a5949cc59771424cb809af5c9f279f78a58.zip
add oauth2/oidc lib
Diffstat (limited to 'library/oauth2/src/OAuth2/Response.php')
-rw-r--r--library/oauth2/src/OAuth2/Response.php369
1 files changed, 369 insertions, 0 deletions
diff --git a/library/oauth2/src/OAuth2/Response.php b/library/oauth2/src/OAuth2/Response.php
new file mode 100644
index 000000000..d8eabe79e
--- /dev/null
+++ b/library/oauth2/src/OAuth2/Response.php
@@ -0,0 +1,369 @@
+<?php
+
+namespace OAuth2;
+
+/**
+ * Class to handle OAuth2 Responses in a graceful way. Use this interface
+ * to output the proper OAuth2 responses.
+ *
+ * @see OAuth2\ResponseInterface
+ *
+ * This class borrows heavily from the Symfony2 Framework and is part of the symfony package
+ * @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony)
+ */
+class Response implements ResponseInterface
+{
+ public $version;
+ protected $statusCode = 200;
+ protected $statusText;
+ protected $parameters = array();
+ protected $httpHeaders = array();
+
+ public static $statusTexts = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ );
+
+ public function __construct($parameters = array(), $statusCode = 200, $headers = array())
+ {
+ $this->setParameters($parameters);
+ $this->setStatusCode($statusCode);
+ $this->setHttpHeaders($headers);
+ $this->version = '1.1';
+ }
+
+ /**
+ * Converts the response object to string containing all headers and the response content.
+ *
+ * @return string The response with headers and content
+ */
+ public function __toString()
+ {
+ $headers = array();
+ foreach ($this->httpHeaders as $name => $value) {
+ $headers[$name] = (array) $value;
+ }
+
+ return
+ sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
+ $this->getHttpHeadersAsString($headers)."\r\n".
+ $this->getResponseBody();
+ }
+
+ /**
+ * Returns the build header line.
+ *
+ * @param string $name The header name
+ * @param string $value The header value
+ *
+ * @return string The built header line
+ */
+ protected function buildHeader($name, $value)
+ {
+ return sprintf("%s: %s\n", $name, $value);
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function setStatusCode($statusCode, $text = null)
+ {
+ $this->statusCode = (int) $statusCode;
+ if ($this->isInvalid()) {
+ throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
+ }
+
+ $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
+ }
+
+ public function getStatusText()
+ {
+ return $this->statusText;
+ }
+
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ public function setParameters(array $parameters)
+ {
+ $this->parameters = $parameters;
+ }
+
+ public function addParameters(array $parameters)
+ {
+ $this->parameters = array_merge($this->parameters, $parameters);
+ }
+
+ public function getParameter($name, $default = null)
+ {
+ return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
+ }
+
+ public function setParameter($name, $value)
+ {
+ $this->parameters[$name] = $value;
+ }
+
+ public function setHttpHeaders(array $httpHeaders)
+ {
+ $this->httpHeaders = $httpHeaders;
+ }
+
+ public function setHttpHeader($name, $value)
+ {
+ $this->httpHeaders[$name] = $value;
+ }
+
+ public function addHttpHeaders(array $httpHeaders)
+ {
+ $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
+ }
+
+ public function getHttpHeaders()
+ {
+ return $this->httpHeaders;
+ }
+
+ public function getHttpHeader($name, $default = null)
+ {
+ return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
+ }
+
+ public function getResponseBody($format = 'json')
+ {
+ switch ($format) {
+ case 'json':
+ return json_encode($this->parameters);
+ case 'xml':
+ // this only works for single-level arrays
+ $xml = new \SimpleXMLElement('<response/>');
+ foreach ($this->parameters as $key => $param) {
+ $xml->addChild($key, $param);
+ }
+
+ return $xml->asXML();
+ }
+
+ throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format));
+
+ }
+
+ public function send($format = 'json')
+ {
+ // headers have already been sent by the developer
+ if (headers_sent()) {
+ return;
+ }
+
+ switch ($format) {
+ case 'json':
+ $this->setHttpHeader('Content-Type', 'application/json');
+ break;
+ case 'xml':
+ $this->setHttpHeader('Content-Type', 'text/xml');
+ break;
+ }
+ // status
+ header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
+
+ foreach ($this->getHttpHeaders() as $name => $header) {
+ header(sprintf('%s: %s', $name, $header));
+ }
+ echo $this->getResponseBody($format);
+ }
+
+ public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
+ {
+ $parameters = array(
+ 'error' => $error,
+ 'error_description' => $errorDescription,
+ );
+
+ if (!is_null($errorUri)) {
+ if (strlen($errorUri) > 0 && $errorUri[0] == '#') {
+ // we are referencing an oauth bookmark (for brevity)
+ $errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri;
+ }
+ $parameters['error_uri'] = $errorUri;
+ }
+
+ $httpHeaders = array(
+ 'Cache-Control' => 'no-store'
+ );
+
+ $this->setStatusCode($statusCode);
+ $this->addParameters($parameters);
+ $this->addHttpHeaders($httpHeaders);
+
+ if (!$this->isClientError() && !$this->isServerError()) {
+ throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
+ }
+ }
+
+ public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
+ {
+ if (empty($url)) {
+ throw new \InvalidArgumentException('Cannot redirect to an empty URL.');
+ }
+
+ $parameters = array();
+
+ if (!is_null($state)) {
+ $parameters['state'] = $state;
+ }
+
+ if (!is_null($error)) {
+ $this->setError(400, $error, $errorDescription, $errorUri);
+ }
+ $this->setStatusCode($statusCode);
+ $this->addParameters($parameters);
+
+ if (count($this->parameters) > 0) {
+ // add parameters to URL redirection
+ $parts = parse_url($url);
+ $sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?';
+ $url .= $sep . http_build_query($this->parameters);
+ }
+
+ $this->addHttpHeaders(array('Location' => $url));
+
+ if (!$this->isRedirection()) {
+ throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
+ }
+ }
+
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isInvalid()
+ {
+ return $this->statusCode < 100 || $this->statusCode >= 600;
+ }
+
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isInformational()
+ {
+ return $this->statusCode >= 100 && $this->statusCode < 200;
+ }
+
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isSuccessful()
+ {
+ return $this->statusCode >= 200 && $this->statusCode < 300;
+ }
+
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isRedirection()
+ {
+ return $this->statusCode >= 300 && $this->statusCode < 400;
+ }
+
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isClientError()
+ {
+ return $this->statusCode >= 400 && $this->statusCode < 500;
+ }
+
+ /**
+ * @return Boolean
+ *
+ * @api
+ */
+ public function isServerError()
+ {
+ return $this->statusCode >= 500 && $this->statusCode < 600;
+ }
+
+ /*
+ * Functions from Symfony2 HttpFoundation - output pretty header
+ */
+ private function getHttpHeadersAsString($headers)
+ {
+ if (count($headers) == 0) {
+ return '';
+ }
+
+ $max = max(array_map('strlen', array_keys($headers))) + 1;
+ $content = '';
+ ksort($headers);
+ foreach ($headers as $name => $values) {
+ foreach ($values as $value) {
+ $content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value);
+ }
+ }
+
+ return $content;
+ }
+
+ private function beautifyHeaderName($name)
+ {
+ return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
+ }
+
+ private function beautifyCallback($match)
+ {
+ return '-'.strtoupper($match[1]);
+ }
+}