Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/apps.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrançois Kooman <fkooman@tuxed.net>2013-07-05 15:23:53 +0400
committerFrançois Kooman <fkooman@tuxed.net>2013-07-05 15:23:53 +0400
commit5a5d9072c5b00d5d62f30090feec97e87746916a (patch)
tree3947bb2d19f54376a7a82d8b4c04e7103e5af5ae /user_oauth
parentee3c7760a9571041e250dc8e4ec49f8b59b33e34 (diff)
update user_oauth to support token introspection (draft-richer-oauth-introspection) and use new php-oauth-lib-rs + API
Diffstat (limited to 'user_oauth')
-rw-r--r--user_oauth/3rdparty/fetch_3rdparty_libs.sh6
-rw-r--r--user_oauth/3rdparty/php-lib-remote-rs/README.md48
-rw-r--r--user_oauth/3rdparty/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php390
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/README.md126
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/draft-richer-oauth-introspection-03.txt336
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/rfc6750.txt1011
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/lib/OAuth/RemoteResourceServer.php467
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/RemoteResourceServerTest.php160
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/TokenIntrospectionTest.php93
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/001.json12
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/002.json8
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/003.json3
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/004.json19
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/100.json3
-rw-r--r--user_oauth/3rdparty/php-oauth-lib-rs/tests/data/101.json1
-rw-r--r--user_oauth/README.md68
-rw-r--r--user_oauth/ajax/seturl.php2
-rw-r--r--user_oauth/appinfo/version2
-rw-r--r--user_oauth/js/admin.js4
-rw-r--r--user_oauth/oauth.php55
-rw-r--r--user_oauth/remote.php6
-rw-r--r--user_oauth/settings.php2
-rw-r--r--user_oauth/templates/settings.php4
23 files changed, 2303 insertions, 523 deletions
diff --git a/user_oauth/3rdparty/fetch_3rdparty_libs.sh b/user_oauth/3rdparty/fetch_3rdparty_libs.sh
index 743755a4e..5b97c8033 100644
--- a/user_oauth/3rdparty/fetch_3rdparty_libs.sh
+++ b/user_oauth/3rdparty/fetch_3rdparty_libs.sh
@@ -1,4 +1,4 @@
#!/bin/sh
-rm -rf php-lib-remote-rs/
-git clone https://github.com/fkooman/php-lib-remote-rs.git
-rm -rf php-lib-remote-rs/.git
+rm -rf php-oauth-lib-rs/
+git clone https://github.com/fkooman/php-oauth-lib-rs.git
+rm -rf php-oauth-lib-rs/.git
diff --git a/user_oauth/3rdparty/php-lib-remote-rs/README.md b/user_oauth/3rdparty/php-lib-remote-rs/README.md
deleted file mode 100644
index 0e9d042e4..000000000
--- a/user_oauth/3rdparty/php-lib-remote-rs/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Introduction
-This is a library to implement an OAuth 2.0 resource server (RS). The library
-can be used by any service that wants to accept OAuth 2.0 bearer tokens.
-
-It is compatible with and was tested with
-[php-oauth](https://github.com/fkooman/php-oauth), and should work with Google.
-
-# License
-Licensed under the Apache License, Version 2.0;
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-# API
-Using the library is straightforward:
-
- <?php
- require_once 'extlib/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php';
-
- use \OAuth\RemoteResourceServer as RemoteResourceServer;
-
- $config = array(
- "tokenInfoEndpoint" => "http://localhost/php-oauth/tokeninfo.php",
- "resourceServerRealm" => "My Demo Service",
- "throwException" => FALSE
- );
-
- $rs = new RemoteResourceServer($config);
- $rs->verifyRequest();
-
-Onlt the `tokenInfoEndpoint` configuration parameter is required, the others
-are optional:
-
-* `tokenInfoEndpoint` - specify the location at which to verify the OAuth token;
-* `resourceServerRealm` - specify the "realm" of the RS that is used when
- returning errors to the client using the `WWW-Authenticate` header;
-* `throwException` - throw a `RemoteResourceServerException` instead of handling
- the failure in the library by sending a response back to the client. This is
- useful if you want to integrate the library in your own framework, you can
- use the information from the exception to craft your own response.
-
-After the `verifyRequest()` some methods are available to retrieve information
-about the resource owner and client.
-
-* `getResourceOwnerId()` (the unique resource owner identifier)
-* `getAttributes()` (additional attributes associated with the resource owner)
-* `getScope()` (the scope granted to the client accessing this resource)
-* `getEntitlement()` (the entitlement the resource owner has when accessing this
- resource)
diff --git a/user_oauth/3rdparty/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php b/user_oauth/3rdparty/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php
deleted file mode 100644
index f33d5ad9d..000000000
--- a/user_oauth/3rdparty/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php
+++ /dev/null
@@ -1,390 +0,0 @@
-<?php
-
-/**
- * Copyright 2012 François Kooman <fkooman@tuxed.net>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace OAuth;
-
-class RemoteResourceServer
-{
- private $_config;
-
- private $_grantedScope;
- private $_resourceOwnerId;
- private $_resourceOwnerAttributes;
- private $_isVerified;
-
- public function __construct(array $c)
- {
- $this->_config = $c;
-
- $this->_resourceOwnerId = NULL;
- $this->_grantedScope = NULL;
- $this->_resourceOwnerAttributes = NULL;
- $this->_isVerified = FALSE;
- }
-
- /**
- * Verify the Authorization Bearer token.
- *
- * Note: this only works on Apache as the PHP function
- * "apache_request_headers" is used. On other web servers, or when using
- * a framework, please use the verifyAuthorizationHeader function instead
- * where you can directly specify the contents of the Authorization header.
- */
- public function verifyRequest()
- {
- $apacheHeaders = apache_request_headers();
- $headerKeys = array_keys($apacheHeaders);
- $keyPositionInArray = array_search(strtolower("Authorization"), array_map('strtolower', $headerKeys));
- $authorizationHeader = (FALSE !== $keyPositionInArray) ? $apacheHeaders[$headerKeys[$keyPositionInArray]] : NULL;
- $this->verifyAuthorization($authorizationHeader, $_GET);
- }
-
- public function verifyAuthorization($authorizationHeader = NULL, array $queryParameters = NULL)
- {
- // FIXME: only one authorization mechanism should be allowed
- if (NULL !== $authorizationHeader) {
- $this->verifyAuthorizationHeader($authorizationHeader);
-
- return;
- }
- if (array_key_exists('access_token', $queryParameters)) {
- $this->verifyQueryParameter($queryParameters);
-
- return;
- }
- $this->_handleException("no_token", "no access token provided");
- }
-
- public function verifyQueryParameter(array $queryParameters)
- {
- if (!array_key_exists('access_token', $queryParameters)) {
- $this->_handleException("no_token", "no access token in query parameter");
- }
- $this->verifyBearerToken($queryParameters['access_token']);
- }
-
- /**
- * Verify the Authorization Bearer token.
- *
- * @param $authorizationHeader The actual content of the Authorization
- * header, e.g.: "Bearer abcdef"
- */
- public function verifyAuthorizationHeader($authorizationHeader)
- {
- if (NULL === $authorizationHeader) {
- $this->_handleException("no_token", "no authorization header");
- }
- // b64token = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
- $b64TokenRegExp = '(?:[[:alpha:][:digit:]-._~+/]+=*)';
- $result = preg_match('|^Bearer (?P<value>' . $b64TokenRegExp . ')$|', $authorizationHeader, $matches);
- if ($result === FALSE || $result === 0) {
- $this->_handleException("invalid_token", "the access token is malformed");
- }
- $accessToken = $matches['value'];
- $this->verifyBearerToken($accessToken);
- }
-
- public function verifyBearerToken($accessToken)
- {
- $getParameters = array();
- $getParameters["access_token"] = $accessToken;
-
- $curlChannel = curl_init();
-
- $tokenInfoUrl = $this->_getRequiredConfigParameter("tokenInfoEndpoint");
- if (0 !== strpos($tokenInfoUrl, "file://")) {
- $separator = (FALSE === strpos($tokenInfoUrl, "?")) ? "?" : "&";
- $tokenInfoUrl .= $separator . http_build_query($getParameters);
- } else {
- // file cannot have query parameter, use accesstoken as file instead
- $tokenInfoUrl .= $accessToken . ".json";
- }
- curl_setopt_array($curlChannel, array (
- CURLOPT_URL => $tokenInfoUrl,
- //CURLOPT_FOLLOWLOCATION => 1,
- CURLOPT_RETURNTRANSFER => 1,
- CURLOPT_SSL_VERIFYPEER => 1,
- CURLOPT_SSL_VERIFYHOST => 2,
- ));
-
- $output = curl_exec($curlChannel);
-
- if (FALSE === $output) {
- $error = curl_error($curlChannel);
- $this->_handleException("internal_server_error", "cURL error while talking to tokenInfoEndpoint: $error");
- }
-
- $httpCode = curl_getinfo($curlChannel, CURLINFO_HTTP_CODE);
- curl_close($curlChannel);
-
- if (0 !== strpos($tokenInfoUrl, "file://")) {
- // not a file
- if (200 !== $httpCode) {
- $this->_handleException("invalid_token", "the access token is not valid");
- }
- }
-
- $token = json_decode($output, TRUE);
- if (NULL === $token) {
- $this->_handleException("internal_server_error", "unable to decode the token response from authorization server");
- }
-
- if ($token['expires_in'] < 0) {
- $this->_handleException("invalid_token", "the access token expired");
- }
-
- $this->_resourceOwnerId = $token['user_id'];
- $this->_grantedScope = $token['scope'];
- $this->_resourceOwnerAttributes = $token['attributes'];
-
- $this->_isVerified = TRUE;
- }
-
- public function getResourceOwnerId()
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
-
- return $this->_resourceOwnerId;
- }
-
- public function getScope()
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- if (NULL === $this->_grantedScope) {
- return array();
- }
-
- return explode(" ", $this->_grantedScope);
- }
-
- public function getEntitlement()
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- if (!array_key_exists('eduPersonEntitlement', $this->_resourceOwnerAttributes)) {
- return array();
- }
-
- return $this->_resourceOwnerAttributes['eduPersonEntitlement'];
- }
-
- public function hasScope($scope)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- if (NULL === $this->_grantedScope) {
- return FALSE;
- }
- $grantedScope = explode(" ", $this->_grantedScope);
- if (in_array($scope, $grantedScope)) {
- return TRUE;
- }
-
- return FALSE;
- }
-
- public function requireScope($scope)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- if (FALSE === $this->hasScope($scope)) {
- $this->_handleException("insufficient_scope", "no permission for this call with granted scope");
- }
- }
-
- /**
- * At least one of the scopes should be granted
- *
- * @param array $scope the list of scopes of which one
- * should be granted
- * @throws RemoteResourceServerException if not at least one of the provided
- * scopes was granted
- */
- public function requireAnyScope(array $scope)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- foreach ($scope as $s) {
- if (TRUE === $this->hasScope($s)) {
- return;
- }
- }
- $this->_handleException("insufficient_scope", "no permission for this call with granted scope");
- }
-
- public function hasEntitlement($entitlement)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- if (!array_key_exists('eduPersonEntitlement', $this->_resourceOwnerAttributes)) {
- return FALSE;
- }
-
- return in_array($entitlement, $this->_resourceOwnerAttributes['eduPersonEntitlement']);
- }
-
- public function requireEntitlement($entitlement)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
-
- if (FALSE === $this->hasEntitlement($entitlement)) {
- $this->_handleException("insufficient_entitlement", "no permission for this call with granted entitlement");
- }
- }
-
- public function getAttributes()
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
-
- return $this->_resourceOwnerAttributes;
- }
-
- public function getAttribute($key)
- {
- if (!$this->_isVerified) {
- $this->_handleException("internal_server_error", "verify method needs to be requested first");
- }
- $attributes = $this->getAttributes();
-
- return array_key_exists($key, $attributes) ? $attributes[$key] : NULL;
- }
-
- private function _getRequiredConfigParameter($key)
- {
- if (!array_key_exists($key, $this->_config)) {
- $this->_handleException("internal_server_error", "no config parameter '$key'");
- }
-
- return $this->_config[$key];
- }
-
- private function _handleException($message, $description)
- {
- switch ($message) {
- case "no_token":
- case "invalid_token":
- $responseCode = 401;
- break;
- case "insufficient_scope":
- case "insufficient_entitlement":
- $responseCode = 403;
- break;
- case "internal_server_error":
- $responseCode = 500;
- break;
- case "invalid_request":
- default:
- $responseCode = 400;
- break;
- }
-
- $resourceServerRealm = array_key_exists("resourceServerRealm", $this->_config) ? $this->_config["resourceServerRealm"] : "Resource Server";
-
- $content = json_encode(array("error" => $message, "error_description" => $description));
- $authenticateHeader = NULL;
-
- if (500 !== $responseCode) {
- if ("no_token" === $message) {
- // no authorization header is a special case, the client did not know
- // authentication was required, so tell it now without giving error message
- $authenticateHeader = 'Bearer realm="' . $resourceServerRealm . '"';
- } else {
- $authenticateHeader = sprintf('Bearer realm="' . $resourceServerRealm . '",error="%s",error_description="%s"', $message, $description);
- }
- }
-
- // we can either throw an exception in case a framework is used, or just
- // directly handle the response to the client ourselves...
- if (array_key_exists("throwException", $this->_config) && $this->_config["throwException"]) {
- $e = new RemoteResourceServerException($message, $description);
- $e->setResponseCode($responseCode);
- $e->setAuthenticateHeader($authenticateHeader);
- $e->setContent($content);
- throw $e;
- } else {
- header("HTTP/1.1 " . $responseCode);
- header("WWW-Authenticate: " . $authenticateHeader);
- header("Content-Type: application/json");
- die($content);
- }
- }
-
-}
-
-class RemoteResourceServerException extends \Exception
-{
- private $_description;
- private $_responseCode;
- private $_authenticateHeader;
- private $_content;
-
- public function __construct($message, $description, $code = 0, Exception $previous = null)
- {
- $this->_description = $description;
- parent::__construct($message, $code, $previous);
- }
-
- public function getDescription()
- {
- return $this->_description;
- }
-
- public function setResponseCode($responseCode)
- {
- $this->_responseCode = $responseCode;
- }
-
- public function getResponseCode()
- {
- return $this->_responseCode;
- }
-
- public function setAuthenticateHeader($authenticateHeader)
- {
- $this->_authenticateHeader = $authenticateHeader;
- }
-
- public function getAuthenticateHeader()
- {
- return $this->_authenticateHeader;
- }
-
- public function setContent($content)
- {
- $this->_content = $content;
- }
-
- public function getContent()
- {
- return $this->_content;
- }
-
-}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/README.md b/user_oauth/3rdparty/php-oauth-lib-rs/README.md
new file mode 100644
index 000000000..584255ac1
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/README.md
@@ -0,0 +1,126 @@
+# Introduction
+This is a library to implement an OAuth 2.0 resource server (RS). The library
+can be used by any service that wants to accept OAuth 2.0 bearer tokens.
+
+It is compatible with and was tested with
+[php-oauth](https://github.com/fkooman/php-oauth).
+
+# License
+Licensed under the Apache License, Version 2.0;
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+# API
+Using the library is straightforward:
+
+ <?php
+ require_once 'lib/OAuth/RemoteResourceServer.php';
+
+ use \OAuth\RemoteResourceServer as RemoteResourceServer;
+
+ $config = array(
+ "introspectionEndpoint" => "http://localhost/php-oauth/introspect.php",
+ );
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyAndHandleRequest();
+
+ header("Content-Type: text/plain");
+ echo $introspection->getSub(); // resourceOwnerId
+
+Only the `introspectionEndpoint` configuration parameter needs to be set.
+
+* `introspectionEndpoint` (REQUIRED) specify the location at which to verify
+ the OAuth token;
+* `realm` (OPTIONAL) specify the "realm" of the RS that is used when
+ returning errors to the client using the `WWW-Authenticate` header. Default
+ value is `Resource Server`;
+
+## Verify Tokens
+If you write a simple piece of software that does not use any framework for
+handling HTTP requests and responses you can use the following method to handle
+all communication with the client by itself:
+
+ verifyAndHandleRequest()
+
+This will extract the Bearer Authorization header or `access_token` query
+parameter, verify it at the introspection endpoint and inform the client
+directly about any problems.
+
+If you use a HTTP framework an other method is available to help you verify
+tokens:
+
+ verifyRequest(array $requestHeaders, array $queryParameters)
+
+You can specify an array with request headers and an array with query
+parameters. You can just feed the library all request headers and query
+parameters as only the relevant `Authorization` and/or `access_token`
+query parameter are evaluated. If the client provides both an `Authorization`
+header and an `access_token` query parameter an error will be returned as it
+is not allowed to specify both methods simultaneously.
+
+## Retrieve Resource Owner Information
+After the `verifyRequest()`, or any of the other verify functions, some methods
+may be available to retrieve information about the resource owner and client
+assuming the verification was successful and the token introspection endpoint
+provides this information to the resource server.
+
+* `getResourceOwnerId()` (the unique resource owner identifier)
+* `getScope()` (the scope granted to the client accessing this resource)
+* `getEntitlement()` (the entitlement the resource owner has when accessing this
+ resource)
+* `getExt()` (get additional data set by the authentication plugin. For instance
+ the SspResourceOwner class uses this to store the SAML attributes obtained from
+ the identity provider)
+
+Note that the `getEntitlement()` and `getExt()` methods are not supported by all
+authorization servers and is a proprietary extension to
+[https://github.com/fkooman/php-oauth](php-oauth). There are more methods that
+can help with implementing a resource server more efficiently, see the
+`TokenIntrospection` class documentation.
+
+## Exceptions
+The library will return exceptions when using the `verifyRequest` method, you
+can catch these exceptions and send the appropriate response to the client
+using your own (HTTP) framework.
+
+The exception provides some helper methods to help with constructing a response
+for the client:
+
+* `getResponseCode()`
+* `getAuthenticateHeader()`
+* `setRealm($realm)`
+* `getContent()`
+
+The `getResponseCode()` method will get you the (integer) HTTP response code
+to send to the client. The method `setRealm($realm)` allows you to set the
+"realm" that will be part of the `WWW-Authenticate` header you can retrieve
+with the `getAuthenticateHeader()` method. The `getContent()` method gives you
+a `JSON` formatted response you can send back to the client, this is OPTIONAL.
+
+Here is an example on how to use this library with your own exception handling:
+
+ <?php
+ require_once 'lib/OAuth/RemoteResourceServer.php';
+
+ use \OAuth\RemoteResourceServer as RemoteResourceServer;
+ use \OAuth\RemoteResourceServerException as RemoteResourceServerException;
+
+ $config = array(
+ "introspectionEndpoint" => "http://localhost/php-oauth/introspect.php",
+ );
+
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(apache_request_headers(), $_GET);
+ header("Content-Type: text/plain");
+ echo $introspection->getSub();
+ } catch (RemoteResourceServerException $e) {
+ $e->setRealm("Foo");
+ header("HTTP/1.1 " . $e->getResponseCode());
+ if (NULL !== $e->getAuthenticateHeader()) {
+ // for "internal_server_error" responses no WWW-Authenticate header is set
+ header("WWW-Authenticate: " . $e->getAuthenticateHeader());
+ }
+ header("Content-Type: application/json");
+ die($e->getContent());
+ }
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/draft-richer-oauth-introspection-03.txt b/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/draft-richer-oauth-introspection-03.txt
new file mode 100644
index 000000000..8cad751e9
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/draft-richer-oauth-introspection-03.txt
@@ -0,0 +1,336 @@
+
+
+
+OAuth Working Group J. Richer, Ed.
+Internet-Draft The MITRE Corporation
+Intended status: Standards Track February 21, 2013
+Expires: August 25, 2013
+
+
+ OAuth Token Introspection
+ draft-richer-oauth-introspection-03
+
+Abstract
+
+ This specification defines a method for a client or protected
+ resource to query an OAuth authorization server to determine meta-
+ information about an OAuth token.
+
+Requirements Language
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+Status of this Memo
+
+ This Internet-Draft is submitted in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF). Note that other groups may also distribute
+ working documents as Internet-Drafts. The list of current Internet-
+ Drafts is at http://datatracker.ietf.org/drafts/current/.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ This Internet-Draft will expire on August 25, 2013.
+
+Copyright Notice
+
+ Copyright (c) 2013 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+
+
+
+Richer Expires August 25, 2013 [Page 1]
+
+Internet-Draft oauth-introspection February 2013
+
+
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Introspection Endpoint . . . . . . . . . . . . . . . . . . . . 3
+ 2.1. Introspection Request . . . . . . . . . . . . . . . . . . . 3
+ 2.2. Introspection Response . . . . . . . . . . . . . . . . . . 4
+ 2.3. Non-normative Example . . . . . . . . . . . . . . . . . . . 4
+ 3. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 6
+ 4. Security Considerations . . . . . . . . . . . . . . . . . . . . 6
+ 5. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 6
+ 6. Normative References . . . . . . . . . . . . . . . . . . . . . 6
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Richer Expires August 25, 2013 [Page 2]
+
+Internet-Draft oauth-introspection February 2013
+
+
+1. Introduction
+
+ In OAuth, the contents of tokens are opaque to clients. This means
+ that the client does not need to know anything about the content or
+ structure of the token itself, if there is any. However, there is
+ still a large amount of metadata that may be attached to a token,
+ such as its current validity, approved scopes, and extra information
+ about the authentication context in which the token was issued.
+ These pieces of information are often vital to Protected Resources
+ making authorization decisions based on the tokens being presented.
+ Since OAuth2 defines no direct relationship between the Authorization
+ Server and the Protected Resource, only that they must have an
+ agreement on the tokens themselves, there have been many different
+ approaches to bridging this gap.
+
+ This specification defines an Introspection Endpoint that allows the
+ holder of a token to query the Authorization Server to discover the
+ set of metadata for a token. A Protected Resource may use the
+ mechanism described in this draft to query the Introspection Endpoint
+ in a particular authorization decision context and ascertain the
+ relevant metadata about the token in order to make this authorization
+ decision appropriately.
+
+
+2. Introspection Endpoint
+
+ The Introspection Endpoint is an OAuth 2 Endpoint that responds to
+ HTTP GET and HTTP POST requests from token holders. The endpoint
+ takes a single parameter representing the token (and optionally
+ further authentication) and returns a JSON document representing the
+ meta information surrounding the token.
+
+2.1. Introspection Request
+
+ token REQUIRED. The string value of the token.
+
+ resource_id OPTIONAL. A service-specific string identifying the
+ resource that the client doing the introspection is asking about.
+
+ The endpoint MAY allow other parameters to provide context to the
+ query. For instance, an authorization service may need to know the
+ IP address of the Client in order to determine the appropriateness of
+ the token being presented.
+
+ The endpoint SHOULD also require some form of authentication to
+ access this endpoint, such as the Client Authentication as described
+ in OAuth 2 Core Specification [RFC6749] or a separate OAuth2 Access
+ Token. The methods of managing and validating these authentication
+
+
+
+Richer Expires August 25, 2013 [Page 3]
+
+Internet-Draft oauth-introspection February 2013
+
+
+ credentials are out of scope of this specification.
+
+2.2. Introspection Response
+
+ The server responds with a JSON object [RFC4627] in
+ "application/json" format with the following top-level members.
+ Specific implementations MAY extend this structure with their own
+ service-specific pieces of information.
+
+ active REQUIRED. Boolean indicator of whether or not the presented
+ token is currently active.
+
+ expires_at OPTIONAL. Integer timestamp, measured in the number of
+ seconds since January 1 1970 UTC, indicating when this token will
+ expire.
+
+ issued_at OPTIONAL. Integer timestamp, measured in the number of
+ seconds since January 1 1970 UTC, indicating when this token was
+ originally issued.
+
+ scope OPTIONAL. A space-separated list of strings representing the
+ scopes associated with this token, in the format described in
+ Section 3.3 of OAuth 2.0 [RFC6749].
+
+ client_id OPTIONAL. Client Identifier for the OAuth Client that
+ requested this token.
+
+ sub OPTIONAL. Local identifier of the Resource Owner who authorized
+ this token.
+
+ aud OPTIONAL. Service-specific string identifier or list of string
+ identifiers representing the intended audience for this token.
+
+2.3. Non-normative Example
+
+ For example, a Protected Resource accepts a request from a Client
+ carrying an OAuth2 Bearer Token. In order to know how and whether to
+ serve the request, the Protected Resource then makes the following
+ request to the Introspection Endpoint of the Authorization Server.
+ The Protected Resource is here authenticating with its own Client ID
+ and Client Secret as per OAuth2 [RFC6749] Section 2.3.1.
+
+
+
+
+
+
+
+
+
+
+Richer Expires August 25, 2013 [Page 4]
+
+Internet-Draft oauth-introspection February 2013
+
+
+ Following is a non-normative example request (with line wraps for
+ display purposes only):
+ POST /register HTTP/1.1
+ Accept: application/x-www-form-urlencoded
+ Host: server.example.com
+ Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3
+
+ token=X3241Affw.4233-99JXJ
+
+ The Authorization Server validates the client credentials and looks
+ up the information in the token. If the token is currently active,
+ it returns the following JSON document.
+
+ Following is a non-normative example active token response (with line
+ wraps for display purposes only):
+ HTTP/1.1 200 OK
+ Content-Type: application/json
+ Cache-Control: no-store
+
+ {
+ "active": true,
+ "client_id":"s6BhdRkqt3",
+ "scope": "read write dolphin",
+ "sub": "2309fj32kl",
+ "aud": "http://example.org/protected-resource/*"
+ }
+
+ If the token presented is not currently active (but the
+ authentication presented is valid), it returns the following JSON
+ document.
+
+ Following is a non-normative example response to an inactive or
+ invalid token (with line wraps for display purposes only):
+ HTTP/1.1 200 OK
+ Content-Type: application/json
+ Cache-Control: no-store
+
+ {
+ "active": false
+ }
+
+ If the client credentials are invalid or there is another error, the
+ Authorization Server responds with an HTTP 400 (Bad Request) as
+ described in OAuth 2.0 section 5.2 [RFC6749].
+
+
+
+
+
+
+
+Richer Expires August 25, 2013 [Page 5]
+
+Internet-Draft oauth-introspection February 2013
+
+
+3. IANA Considerations
+
+ This document makes no request of IANA.
+
+
+4. Security Considerations
+
+ If left unprotected and un-throttled, the Introspection Endpoint
+ could present a means for an attacker to poll a series of possible
+ token values, fishing for a valid token. Therefore, the
+ Authorization Server SHOULD issue special client credentials to any
+ protected resources or clients that need to access the introspection
+ endpoint. These credentials may be used directly at the endpoint, or
+ they may be exchanged for an OAuth2 Access token scoped specifically
+ for the Introspection Endpoint.
+
+
+5. Acknowledgements
+
+ Thanks to the OAuth Working Group and the UMA Working Group for
+ feedback.
+
+
+6. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC4627] Crockford, D., "The application/json Media Type for
+ JavaScript Object Notation (JSON)", RFC 4627, July 2006.
+
+ [RFC6749] Hardt, D., "The OAuth 2.0 Authorization Framework",
+ RFC 6749, October 2012.
+
+ [RFC6750] Jones, M. and D. Hardt, "The OAuth 2.0 Authorization
+ Framework: Bearer Token Usage", RFC 6750, October 2012.
+
+
+Author's Address
+
+ Justin Richer (editor)
+ The MITRE Corporation
+
+ Email: jricher@mitre.org
+
+
+
+
+
+
+
+Richer Expires August 25, 2013 [Page 6]
+
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/rfc6750.txt b/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/rfc6750.txt
new file mode 100644
index 000000000..b433c72a2
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/docs/specifications/rfc6750.txt
@@ -0,0 +1,1011 @@
+
+
+
+
+
+
+Internet Engineering Task Force (IETF) M. Jones
+Request for Comments: 6750 Microsoft
+Category: Standards Track D. Hardt
+ISSN: 2070-1721 Independent
+ October 2012
+
+
+ The OAuth 2.0 Authorization Framework: Bearer Token Usage
+
+Abstract
+
+ This specification describes how to use bearer tokens in HTTP
+ requests to access OAuth 2.0 protected resources. Any party in
+ possession of a bearer token (a "bearer") can use it to get access to
+ the associated resources (without demonstrating possession of a
+ cryptographic key). To prevent misuse, bearer tokens need to be
+ protected from disclosure in storage and in transport.
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 5741.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ http://www.rfc-editor.org/info/rfc6750.
+
+Copyright Notice
+
+ Copyright (c) 2012 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+
+
+
+Jones & Hardt Standards Track [Page 1]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+Table of Contents
+
+ 1. Introduction ....................................................2
+ 1.1. Notational Conventions .....................................3
+ 1.2. Terminology ................................................3
+ 1.3. Overview ...................................................3
+ 2. Authenticated Requests ..........................................4
+ 2.1. Authorization Request Header Field .........................5
+ 2.2. Form-Encoded Body Parameter ................................5
+ 2.3. URI Query Parameter ........................................6
+ 3. The WWW-Authenticate Response Header Field ......................7
+ 3.1. Error Codes ................................................9
+ 4. Example Access Token Response ..................................10
+ 5. Security Considerations ........................................10
+ 5.1. Security Threats ..........................................10
+ 5.2. Threat Mitigation .........................................11
+ 5.3. Summary of Recommendations ................................13
+ 6. IANA Considerations ............................................14
+ 6.1. OAuth Access Token Type Registration ......................14
+ 6.1.1. The "Bearer" OAuth Access Token Type ...............14
+ 6.2. OAuth Extensions Error Registration .......................14
+ 6.2.1. The "invalid_request" Error Value ..................14
+ 6.2.2. The "invalid_token" Error Value ....................15
+ 6.2.3. The "insufficient_scope" Error Value ...............15
+ 7. References .....................................................15
+ 7.1. Normative References ......................................15
+ 7.2. Informative References ....................................17
+ Appendix A. Acknowledgements ......................................18
+
+1. Introduction
+
+ OAuth enables clients to access protected resources by obtaining an
+ access token, which is defined in "The OAuth 2.0 Authorization
+ Framework" [RFC6749] as "a string representing an access
+ authorization issued to the client", rather than using the resource
+ owner's credentials directly.
+
+ Tokens are issued to clients by an authorization server with the
+ approval of the resource owner. The client uses the access token to
+ access the protected resources hosted by the resource server. This
+ specification describes how to make protected resource requests when
+ the OAuth access token is a bearer token.
+
+ This specification defines the use of bearer tokens over HTTP/1.1
+ [RFC2616] using Transport Layer Security (TLS) [RFC5246] to access
+ protected resources. TLS is mandatory to implement and use with this
+ specification; other specifications may extend this specification for
+ use with other protocols. While designed for use with access tokens
+
+
+
+Jones & Hardt Standards Track [Page 2]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ resulting from OAuth 2.0 authorization [RFC6749] flows to access
+ OAuth protected resources, this specification actually defines a
+ general HTTP authorization method that can be used with bearer tokens
+ from any source to access any resources protected by those bearer
+ tokens. The Bearer authentication scheme is intended primarily for
+ server authentication using the WWW-Authenticate and Authorization
+ HTTP headers but does not preclude its use for proxy authentication.
+
+1.1. Notational Conventions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in "Key words for use in
+ RFCs to Indicate Requirement Levels" [RFC2119].
+
+ This document uses the Augmented Backus-Naur Form (ABNF) notation of
+ [RFC5234]. Additionally, the following rules are included from
+ HTTP/1.1 [RFC2617]: auth-param and auth-scheme; and from "Uniform
+ Resource Identifier (URI): Generic Syntax" [RFC3986]: URI-reference.
+
+ Unless otherwise noted, all the protocol parameter names and values
+ are case sensitive.
+
+1.2. Terminology
+
+ Bearer Token
+ A security token with the property that any party in possession of
+ the token (a "bearer") can use the token in any way that any other
+ party in possession of it can. Using a bearer token does not
+ require a bearer to prove possession of cryptographic key material
+ (proof-of-possession).
+
+ All other terms are as defined in "The OAuth 2.0 Authorization
+ Framework" [RFC6749].
+
+1.3. Overview
+
+ OAuth provides a method for clients to access a protected resource on
+ behalf of a resource owner. In the general case, before a client can
+ access a protected resource, it must first obtain an authorization
+ grant from the resource owner and then exchange the authorization
+ grant for an access token. The access token represents the grant's
+ scope, duration, and other attributes granted by the authorization
+ grant. The client accesses the protected resource by presenting the
+ access token to the resource server. In some cases, a client can
+ directly present its own credentials to an authorization server to
+ obtain an access token without having to first obtain an
+ authorization grant from a resource owner.
+
+
+
+Jones & Hardt Standards Track [Page 3]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ The access token provides an abstraction, replacing different
+ authorization constructs (e.g., username and password, assertion) for
+ a single token understood by the resource server. This abstraction
+ enables issuing access tokens valid for a short time period, as well
+ as removing the resource server's need to understand a wide range of
+ authentication schemes.
+
+ +--------+ +---------------+
+ | |--(A)- Authorization Request ->| Resource |
+ | | | Owner |
+ | |<-(B)-- Authorization Grant ---| |
+ | | +---------------+
+ | |
+ | | +---------------+
+ | |--(C)-- Authorization Grant -->| Authorization |
+ | Client | | Server |
+ | |<-(D)----- Access Token -------| |
+ | | +---------------+
+ | |
+ | | +---------------+
+ | |--(E)----- Access Token ------>| Resource |
+ | | | Server |
+ | |<-(F)--- Protected Resource ---| |
+ +--------+ +---------------+
+
+ Figure 1: Abstract Protocol Flow
+
+ The abstract OAuth 2.0 flow illustrated in Figure 1 describes the
+ interaction between the client, resource owner, authorization server,
+ and resource server (described in [RFC6749]). The following two
+ steps are specified within this document:
+
+ (E) The client requests the protected resource from the resource
+ server and authenticates by presenting the access token.
+
+ (F) The resource server validates the access token, and if valid,
+ serves the request.
+
+ This document also imposes semantic requirements upon the access
+ token returned in step (D).
+
+2. Authenticated Requests
+
+ This section defines three methods of sending bearer access tokens in
+ resource requests to resource servers. Clients MUST NOT use more
+ than one method to transmit the token in each request.
+
+
+
+
+
+Jones & Hardt Standards Track [Page 4]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+2.1. Authorization Request Header Field
+
+ When sending the access token in the "Authorization" request header
+ field defined by HTTP/1.1 [RFC2617], the client uses the "Bearer"
+ authentication scheme to transmit the access token.
+
+ For example:
+
+ GET /resource HTTP/1.1
+ Host: server.example.com
+ Authorization: Bearer mF_9.B5f-4.1JqM
+
+ The syntax of the "Authorization" header field for this scheme
+ follows the usage of the Basic scheme defined in Section 2 of
+ [RFC2617]. Note that, as with Basic, it does not conform to the
+ generic syntax defined in Section 1.2 of [RFC2617] but is compatible
+ with the general authentication framework being developed for
+ HTTP 1.1 [HTTP-AUTH], although it does not follow the preferred
+ practice outlined therein in order to reflect existing deployments.
+ The syntax for Bearer credentials is as follows:
+
+ b64token = 1*( ALPHA / DIGIT /
+ "-" / "." / "_" / "~" / "+" / "/" ) *"="
+ credentials = "Bearer" 1*SP b64token
+
+ Clients SHOULD make authenticated requests with a bearer token using
+ the "Authorization" request header field with the "Bearer" HTTP
+ authorization scheme. Resource servers MUST support this method.
+
+2.2. Form-Encoded Body Parameter
+
+ When sending the access token in the HTTP request entity-body, the
+ client adds the access token to the request-body using the
+ "access_token" parameter. The client MUST NOT use this method unless
+ all of the following conditions are met:
+
+ o The HTTP request entity-header includes the "Content-Type" header
+ field set to "application/x-www-form-urlencoded".
+
+ o The entity-body follows the encoding requirements of the
+ "application/x-www-form-urlencoded" content-type as defined by
+ HTML 4.01 [W3C.REC-html401-19991224].
+
+ o The HTTP request entity-body is single-part.
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 5]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ o The content to be encoded in the entity-body MUST consist entirely
+ of ASCII [USASCII] characters.
+
+ o The HTTP request method is one for which the request-body has
+ defined semantics. In particular, this means that the "GET"
+ method MUST NOT be used.
+
+ The entity-body MAY include other request-specific parameters, in
+ which case the "access_token" parameter MUST be properly separated
+ from the request-specific parameters using "&" character(s) (ASCII
+ code 38).
+
+ For example, the client makes the following HTTP request using
+ transport-layer security:
+
+ POST /resource HTTP/1.1
+ Host: server.example.com
+ Content-Type: application/x-www-form-urlencoded
+
+ access_token=mF_9.B5f-4.1JqM
+
+ The "application/x-www-form-urlencoded" method SHOULD NOT be used
+ except in application contexts where participating browsers do not
+ have access to the "Authorization" request header field. Resource
+ servers MAY support this method.
+
+2.3. URI Query Parameter
+
+ When sending the access token in the HTTP request URI, the client
+ adds the access token to the request URI query component as defined
+ by "Uniform Resource Identifier (URI): Generic Syntax" [RFC3986],
+ using the "access_token" parameter.
+
+ For example, the client makes the following HTTP request using
+ transport-layer security:
+
+ GET /resource?access_token=mF_9.B5f-4.1JqM HTTP/1.1
+ Host: server.example.com
+
+ The HTTP request URI query can include other request-specific
+ parameters, in which case the "access_token" parameter MUST be
+ properly separated from the request-specific parameters using "&"
+ character(s) (ASCII code 38).
+
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 6]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ For example:
+
+ https://server.example.com/resource?access_token=mF_9.B5f-4.1JqM&p=q
+
+ Clients using the URI Query Parameter method SHOULD also send a
+ Cache-Control header containing the "no-store" option. Server
+ success (2XX status) responses to these requests SHOULD contain a
+ Cache-Control header with the "private" option.
+
+ Because of the security weaknesses associated with the URI method
+ (see Section 5), including the high likelihood that the URL
+ containing the access token will be logged, it SHOULD NOT be used
+ unless it is impossible to transport the access token in the
+ "Authorization" request header field or the HTTP request entity-body.
+ Resource servers MAY support this method.
+
+ This method is included to document current use; its use is not
+ recommended, due to its security deficiencies (see Section 5) and
+ also because it uses a reserved query parameter name, which is
+ counter to URI namespace best practices, per "Architecture of the
+ World Wide Web, Volume One" [W3C.REC-webarch-20041215].
+
+3. The WWW-Authenticate Response Header Field
+
+ If the protected resource request does not include authentication
+ credentials or does not contain an access token that enables access
+ to the protected resource, the resource server MUST include the HTTP
+ "WWW-Authenticate" response header field; it MAY include it in
+ response to other conditions as well. The "WWW-Authenticate" header
+ field uses the framework defined by HTTP/1.1 [RFC2617].
+
+ All challenges defined by this specification MUST use the auth-scheme
+ value "Bearer". This scheme MUST be followed by one or more
+ auth-param values. The auth-param attributes used or defined by this
+ specification are as follows. Other auth-param attributes MAY be
+ used as well.
+
+ A "realm" attribute MAY be included to indicate the scope of
+ protection in the manner described in HTTP/1.1 [RFC2617]. The
+ "realm" attribute MUST NOT appear more than once.
+
+ The "scope" attribute is defined in Section 3.3 of [RFC6749]. The
+ "scope" attribute is a space-delimited list of case-sensitive scope
+ values indicating the required scope of the access token for
+ accessing the requested resource. "scope" values are implementation
+ defined; there is no centralized registry for them; allowed values
+ are defined by the authorization server. The order of "scope" values
+ is not significant. In some cases, the "scope" value will be used
+
+
+
+Jones & Hardt Standards Track [Page 7]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ when requesting a new access token with sufficient scope of access to
+ utilize the protected resource. Use of the "scope" attribute is
+ OPTIONAL. The "scope" attribute MUST NOT appear more than once. The
+ "scope" value is intended for programmatic use and is not meant to be
+ displayed to end-users.
+
+ Two example scope values follow; these are taken from the OpenID
+ Connect [OpenID.Messages] and the Open Authentication Technology
+ Committee (OATC) Online Multimedia Authorization Protocol [OMAP]
+ OAuth 2.0 use cases, respectively:
+
+ scope="openid profile email"
+ scope="urn:example:channel=HBO&urn:example:rating=G,PG-13"
+
+ If the protected resource request included an access token and failed
+ authentication, the resource server SHOULD include the "error"
+ attribute to provide the client with the reason why the access
+ request was declined. The parameter value is described in
+ Section 3.1. In addition, the resource server MAY include the
+ "error_description" attribute to provide developers a human-readable
+ explanation that is not meant to be displayed to end-users. It also
+ MAY include the "error_uri" attribute with an absolute URI
+ identifying a human-readable web page explaining the error. The
+ "error", "error_description", and "error_uri" attributes MUST NOT
+ appear more than once.
+
+ Values for the "scope" attribute (specified in Appendix A.4 of
+ [RFC6749]) MUST NOT include characters outside the set %x21 / %x23-5B
+ / %x5D-7E for representing scope values and %x20 for delimiters
+ between scope values. Values for the "error" and "error_description"
+ attributes (specified in Appendixes A.7 and A.8 of [RFC6749]) MUST
+ NOT include characters outside the set %x20-21 / %x23-5B / %x5D-7E.
+ Values for the "error_uri" attribute (specified in Appendix A.9 of
+ [RFC6749]) MUST conform to the URI-reference syntax and thus MUST NOT
+ include characters outside the set %x21 / %x23-5B / %x5D-7E.
+
+ For example, in response to a protected resource request without
+ authentication:
+
+ HTTP/1.1 401 Unauthorized
+ WWW-Authenticate: Bearer realm="example"
+
+
+
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 8]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ And in response to a protected resource request with an
+ authentication attempt using an expired access token:
+
+ HTTP/1.1 401 Unauthorized
+ WWW-Authenticate: Bearer realm="example",
+ error="invalid_token",
+ error_description="The access token expired"
+
+3.1. Error Codes
+
+ When a request fails, the resource server responds using the
+ appropriate HTTP status code (typically, 400, 401, 403, or 405) and
+ includes one of the following error codes in the response:
+
+ invalid_request
+ The request is missing a required parameter, includes an
+ unsupported parameter or parameter value, repeats the same
+ parameter, uses more than one method for including an access
+ token, or is otherwise malformed. The resource server SHOULD
+ respond with the HTTP 400 (Bad Request) status code.
+
+ invalid_token
+ The access token provided is expired, revoked, malformed, or
+ invalid for other reasons. The resource SHOULD respond with
+ the HTTP 401 (Unauthorized) status code. The client MAY
+ request a new access token and retry the protected resource
+ request.
+
+ insufficient_scope
+ The request requires higher privileges than provided by the
+ access token. The resource server SHOULD respond with the HTTP
+ 403 (Forbidden) status code and MAY include the "scope"
+ attribute with the scope necessary to access the protected
+ resource.
+
+ If the request lacks any authentication information (e.g., the client
+ was unaware that authentication is necessary or attempted using an
+ unsupported authentication method), the resource server SHOULD NOT
+ include an error code or other error information.
+
+ For example:
+
+ HTTP/1.1 401 Unauthorized
+ WWW-Authenticate: Bearer realm="example"
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 9]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+4. Example Access Token Response
+
+ Typically, a bearer token is returned to the client as part of an
+ OAuth 2.0 [RFC6749] access token response. An example of such a
+ response is:
+
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+ Cache-Control: no-store
+ Pragma: no-cache
+
+ {
+ "access_token":"mF_9.B5f-4.1JqM",
+ "token_type":"Bearer",
+ "expires_in":3600,
+ "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
+ }
+
+5. Security Considerations
+
+ This section describes the relevant security threats regarding token
+ handling when using bearer tokens and describes how to mitigate these
+ threats.
+
+5.1. Security Threats
+
+ The following list presents several common threats against protocols
+ utilizing some form of tokens. This list of threats is based on NIST
+ Special Publication 800-63 [NIST800-63]. Since this document builds
+ on the OAuth 2.0 Authorization specification [RFC6749], we exclude a
+ discussion of threats that are described there or in related
+ documents.
+
+ Token manufacture/modification: An attacker may generate a bogus
+ token or modify the token contents (such as the authentication or
+ attribute statements) of an existing token, causing the resource
+ server to grant inappropriate access to the client. For example,
+ an attacker may modify the token to extend the validity period; a
+ malicious client may modify the assertion to gain access to
+ information that they should not be able to view.
+
+ Token disclosure: Tokens may contain authentication and attribute
+ statements that include sensitive information.
+
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 10]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ Token redirect: An attacker uses a token generated for consumption
+ by one resource server to gain access to a different resource
+ server that mistakenly believes the token to be for it.
+
+ Token replay: An attacker attempts to use a token that has already
+ been used with that resource server in the past.
+
+5.2. Threat Mitigation
+
+ A large range of threats can be mitigated by protecting the contents
+ of the token by using a digital signature or a Message Authentication
+ Code (MAC). Alternatively, a bearer token can contain a reference to
+ authorization information, rather than encoding the information
+ directly. Such references MUST be infeasible for an attacker to
+ guess; using a reference may require an extra interaction between a
+ server and the token issuer to resolve the reference to the
+ authorization information. The mechanics of such an interaction are
+ not defined by this specification.
+
+ This document does not specify the encoding or the contents of the
+ token; hence, detailed recommendations about the means of
+ guaranteeing token integrity protection are outside the scope of this
+ document. The token integrity protection MUST be sufficient to
+ prevent the token from being modified.
+
+ To deal with token redirect, it is important for the authorization
+ server to include the identity of the intended recipients (the
+ audience), typically a single resource server (or a list of resource
+ servers), in the token. Restricting the use of the token to a
+ specific scope is also RECOMMENDED.
+
+ The authorization server MUST implement TLS. Which version(s) ought
+ to be implemented will vary over time and will depend on the
+ widespread deployment and known security vulnerabilities at the time
+ of implementation. At the time of this writing, TLS version 1.2
+ [RFC5246] is the most recent version, but it has very limited actual
+ deployment and might not be readily available in implementation
+ toolkits. TLS version 1.0 [RFC2246] is the most widely deployed
+ version and will give the broadest interoperability.
+
+ To protect against token disclosure, confidentiality protection MUST
+ be applied using TLS [RFC5246] with a ciphersuite that provides
+ confidentiality and integrity protection. This requires that the
+ communication interaction between the client and the authorization
+ server, as well as the interaction between the client and the
+ resource server, utilize confidentiality and integrity protection.
+ Since TLS is mandatory to implement and to use with this
+ specification, it is the preferred approach for preventing token
+
+
+
+Jones & Hardt Standards Track [Page 11]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ disclosure via the communication channel. For those cases where the
+ client is prevented from observing the contents of the token, token
+ encryption MUST be applied in addition to the usage of TLS
+ protection. As a further defense against token disclosure, the
+ client MUST validate the TLS certificate chain when making requests
+ to protected resources, including checking the Certificate Revocation
+ List (CRL) [RFC5280].
+
+ Cookies are typically transmitted in the clear. Thus, any
+ information contained in them is at risk of disclosure. Therefore,
+ bearer tokens MUST NOT be stored in cookies that can be sent in the
+ clear. See "HTTP State Management Mechanism" [RFC6265] for security
+ considerations about cookies.
+
+ In some deployments, including those utilizing load balancers, the
+ TLS connection to the resource server terminates prior to the actual
+ server that provides the resource. This could leave the token
+ unprotected between the front-end server where the TLS connection
+ terminates and the back-end server that provides the resource. In
+ such deployments, sufficient measures MUST be employed to ensure
+ confidentiality of the token between the front-end and back-end
+ servers; encryption of the token is one such possible measure.
+
+ To deal with token capture and replay, the following recommendations
+ are made: First, the lifetime of the token MUST be limited; one means
+ of achieving this is by putting a validity time field inside the
+ protected part of the token. Note that using short-lived (one hour
+ or less) tokens reduces the impact of them being leaked. Second,
+ confidentiality protection of the exchanges between the client and
+ the authorization server and between the client and the resource
+ server MUST be applied. As a consequence, no eavesdropper along the
+ communication path is able to observe the token exchange.
+ Consequently, such an on-path adversary cannot replay the token.
+ Furthermore, when presenting the token to a resource server, the
+ client MUST verify the identity of that resource server, as per
+ Section 3.1 of "HTTP Over TLS" [RFC2818]. Note that the client MUST
+ validate the TLS certificate chain when making these requests to
+ protected resources. Presenting the token to an unauthenticated and
+ unauthorized resource server or failing to validate the certificate
+ chain will allow adversaries to steal the token and gain unauthorized
+ access to protected resources.
+
+
+
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 12]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+5.3. Summary of Recommendations
+
+ Safeguard bearer tokens: Client implementations MUST ensure that
+ bearer tokens are not leaked to unintended parties, as they will
+ be able to use them to gain access to protected resources. This
+ is the primary security consideration when using bearer tokens and
+ underlies all the more specific recommendations that follow.
+
+ Validate TLS certificate chains: The client MUST validate the TLS
+ certificate chain when making requests to protected resources.
+ Failing to do so may enable DNS hijacking attacks to steal the
+ token and gain unintended access.
+
+ Always use TLS (https): Clients MUST always use TLS [RFC5246]
+ (https) or equivalent transport security when making requests with
+ bearer tokens. Failing to do so exposes the token to numerous
+ attacks that could give attackers unintended access.
+
+ Don't store bearer tokens in cookies: Implementations MUST NOT store
+ bearer tokens within cookies that can be sent in the clear (which
+ is the default transmission mode for cookies). Implementations
+ that do store bearer tokens in cookies MUST take precautions
+ against cross-site request forgery.
+
+ Issue short-lived bearer tokens: Token servers SHOULD issue
+ short-lived (one hour or less) bearer tokens, particularly when
+ issuing tokens to clients that run within a web browser or other
+ environments where information leakage may occur. Using
+ short-lived bearer tokens can reduce the impact of them being
+ leaked.
+
+ Issue scoped bearer tokens: Token servers SHOULD issue bearer tokens
+ that contain an audience restriction, scoping their use to the
+ intended relying party or set of relying parties.
+
+ Don't pass bearer tokens in page URLs: Bearer tokens SHOULD NOT be
+ passed in page URLs (for example, as query string parameters).
+ Instead, bearer tokens SHOULD be passed in HTTP message headers or
+ message bodies for which confidentiality measures are taken.
+ Browsers, web servers, and other software may not adequately
+ secure URLs in the browser history, web server logs, and other
+ data structures. If bearer tokens are passed in page URLs,
+ attackers might be able to steal them from the history data, logs,
+ or other unsecured locations.
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 13]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+6. IANA Considerations
+
+6.1. OAuth Access Token Type Registration
+
+ This specification registers the following access token type in the
+ OAuth Access Token Types registry defined in [RFC6749].
+
+6.1.1. The "Bearer" OAuth Access Token Type
+
+ Type name:
+ Bearer
+
+ Additional Token Endpoint Response Parameters:
+ (none)
+
+ HTTP Authentication Scheme(s):
+ Bearer
+
+ Change controller:
+ IETF
+
+ Specification document(s):
+ RFC 6750
+
+6.2. OAuth Extensions Error Registration
+
+ This specification registers the following error values in the OAuth
+ Extensions Error registry defined in [RFC6749].
+
+6.2.1. The "invalid_request" Error Value
+
+ Error name:
+ invalid_request
+
+ Error usage location:
+ Resource access error response
+
+ Related protocol extension:
+ Bearer access token type
+
+ Change controller:
+ IETF
+
+ Specification document(s):
+ RFC 6750
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 14]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+6.2.2. The "invalid_token" Error Value
+
+ Error name:
+ invalid_token
+
+ Error usage location:
+ Resource access error response
+
+ Related protocol extension:
+ Bearer access token type
+
+ Change controller:
+ IETF
+
+ Specification document(s):
+ RFC 6750
+
+6.2.3. The "insufficient_scope" Error Value
+
+ Error name:
+ insufficient_scope
+
+ Error usage location:
+ Resource access error response
+
+ Related protocol extension:
+ Bearer access token type
+
+ Change controller:
+ IETF
+
+ Specification document(s):
+ RFC 6750
+
+7. References
+
+7.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+ RFC 2246, January 1999.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+
+
+
+Jones & Hardt Standards Track [Page 15]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+ [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
+ S., Leach, P., Luotonen, A., and L. Stewart, "HTTP
+ Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999.
+
+ [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.
+
+ [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifier (URI): Generic Syntax", STD 66,
+ RFC 3986, January 2005.
+
+ [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", STD 68, RFC 5234, January 2008.
+
+ [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer
+ Security (TLS) Protocol Version 1.2", RFC 5246,
+ August 2008.
+
+ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
+ Housley, R., and W. Polk, "Internet X.509 Public Key
+ Infrastructure Certificate and Certificate Revocation
+ List (CRL) Profile", RFC 5280, May 2008.
+
+ [RFC6265] Barth, A., "HTTP State Management Mechanism", RFC 6265,
+ April 2011.
+
+ [RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework",
+ RFC 6749, October 2012.
+
+ [USASCII] American National Standards Institute, "Coded Character
+ Set -- 7-bit American Standard Code for Information
+ Interchange", ANSI X3.4, 1986.
+
+ [W3C.REC-html401-19991224]
+ Raggett, D., Le Hors, A., and I. Jacobs, "HTML 4.01
+ Specification", World Wide Web Consortium
+ Recommendation REC-html401-19991224, December 1999,
+ <http://www.w3.org/TR/1999/REC-html401-19991224>.
+
+ [W3C.REC-webarch-20041215]
+ Jacobs, I. and N. Walsh, "Architecture of the World Wide
+ Web, Volume One", World Wide Web Consortium
+ Recommendation REC-webarch-20041215, December 2004,
+ <http://www.w3.org/TR/2004/REC-webarch-20041215>.
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 16]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+7.2. Informative References
+
+ [HTTP-AUTH] Fielding, R., Ed., and J. Reschke, Ed., "Hypertext
+ Transfer Protocol (HTTP/1.1): Authentication", Work
+ in Progress, October 2012.
+
+ [NIST800-63] Burr, W., Dodson, D., Newton, E., Perlner, R., Polk, T.,
+ Gupta, S., and E. Nabbus, "NIST Special Publication
+ 800-63-1, INFORMATION SECURITY", December 2011,
+ <http://csrc.nist.gov/publications/>.
+
+ [OMAP] Huff, J., Schlacht, D., Nadalin, A., Simmons, J.,
+ Rosenberg, P., Madsen, P., Ace, T., Rickelton-Abdi, C.,
+ and B. Boyer, "Online Multimedia Authorization Protocol:
+ An Industry Standard for Authorized Access to Internet
+ Multimedia Resources", April 2012,
+ <http://www.oatc.us/Standards/Download.aspx>.
+
+ [OpenID.Messages]
+ Sakimura, N., Bradley, J., Jones, M., de Medeiros, B.,
+ Mortimore, C., and E. Jay, "OpenID Connect Messages
+ 1.0", June 2012, <http://openid.net/specs/
+ openid-connect-messages-1_0.html>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 17]
+
+RFC 6750 OAuth 2.0 Bearer Token Usage October 2012
+
+
+Appendix A. Acknowledgements
+
+ The following people contributed to preliminary versions of this
+ document: Blaine Cook (BT), Brian Eaton (Google), Yaron Y. Goland
+ (Microsoft), Brent Goldman (Facebook), Raffi Krikorian (Twitter),
+ Luke Shepard (Facebook), and Allen Tom (Yahoo!). The content and
+ concepts within are a product of the OAuth community, the Web
+ Resource Authorization Profiles (WRAP) community, and the OAuth
+ Working Group. David Recordon created a preliminary version of this
+ specification based upon an early draft of the specification that
+ evolved into OAuth 2.0 [RFC6749]. Michael B. Jones in turn created
+ the first version (00) of this specification using portions of
+ David's preliminary document and edited all subsequent versions.
+
+ The OAuth Working Group has dozens of very active contributors who
+ proposed ideas and wording for this document, including Michael
+ Adams, Amanda Anganes, Andrew Arnott, Derek Atkins, Dirk Balfanz,
+ John Bradley, Brian Campbell, Francisco Corella, Leah Culver, Bill de
+ hOra, Breno de Medeiros, Brian Ellin, Stephen Farrell, Igor Faynberg,
+ George Fletcher, Tim Freeman, Evan Gilbert, Yaron Y. Goland, Eran
+ Hammer, Thomas Hardjono, Dick Hardt, Justin Hart, Phil Hunt, John
+ Kemp, Chasen Le Hara, Barry Leiba, Amos Jeffries, Michael B. Jones,
+ Torsten Lodderstedt, Paul Madsen, Eve Maler, James Manger, Laurence
+ Miao, William J. Mills, Chuck Mortimore, Anthony Nadalin, Axel
+ Nennker, Mark Nottingham, David Recordon, Julian Reschke, Rob
+ Richards, Justin Richer, Peter Saint-Andre, Nat Sakimura, Rob Sayre,
+ Marius Scurtescu, Naitik Shah, Justin Smith, Christian Stuebner,
+ Jeremy Suriel, Doug Tangren, Paul Tarjan, Hannes Tschofenig, Franklin
+ Tse, Sean Turner, Paul Walker, Shane Weeden, Skylar Woodward, and
+ Zachary Zeltsan.
+
+Authors' Addresses
+
+ Michael B. Jones
+ Microsoft
+
+ EMail: mbj@microsoft.com
+ URI: http://self-issued.info/
+
+
+ Dick Hardt
+ Independent
+
+ EMail: dick.hardt@gmail.com
+ URI: http://dickhardt.org/
+
+
+
+
+
+
+Jones & Hardt Standards Track [Page 18]
+
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/lib/OAuth/RemoteResourceServer.php b/user_oauth/3rdparty/php-oauth-lib-rs/lib/OAuth/RemoteResourceServer.php
new file mode 100644
index 000000000..acb8c46b5
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/lib/OAuth/RemoteResourceServer.php
@@ -0,0 +1,467 @@
+<?php
+
+/**
+ * Copyright 2013 François Kooman <fkooman@tuxed.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace OAuth;
+
+class RemoteResourceServer
+{
+ private $_config;
+
+ public function __construct(array $c)
+ {
+ $this->_config = $c;
+ }
+
+ public function verifyAndHandleRequest()
+ {
+ try {
+ $headerBearerToken = NULL;
+ $queryBearerToken = NULL;
+
+ // look for headers
+ if (function_exists("apache_request_headers")) {
+ $headers = apache_request_headers();
+ } elseif (isset($_SERVER)) {
+ $headers = $_SERVER;
+ } else {
+ $headers = array();
+ }
+
+ // look for query parameters
+ $query = (isset($_GET) && is_array($_GET)) ? $_GET : array();
+
+ return $this->verifyRequest($headers, $query);
+
+ } catch (RemoteResourceServerException $e) {
+ // send response directly to client, halt execution of calling script as well
+ $e->setRealm($this->_getConfigParameter("realm", FALSE, "Resource Server"));
+ header("HTTP/1.1 " . $e->getResponseCode());
+ if (NULL !== $e->getAuthenticateHeader()) {
+ // for "internal_server_error" responses no WWW-Authenticate header is set
+ header("WWW-Authenticate: " . $e->getAuthenticateHeader());
+ }
+ header("Content-Type: application/json");
+ die($e->getContent());
+ }
+ }
+
+ public function verifyRequest(array $headers, array $query)
+ {
+ // extract token from authorization header
+ $authorizationHeader = self::_getAuthorizationHeader($headers);
+ $ah = FALSE !== $authorizationHeader ? self::_getTokenFromHeader($authorizationHeader) : FALSE;
+
+ // extract token from query parameters
+ $aq = self::_getTokenFromQuery($query);
+
+ if (FALSE === $ah && FALSE === $aq) {
+ // no token at all provided
+ throw new RemoteResourceServerException("no_token", "missing token");
+ }
+ if (FALSE !== $ah && FALSE !== $aq) {
+ // two tokens provided
+ throw new RemoteResourceServerException("invalid_request", "more than one method for including an access token used");
+ }
+ if (FALSE !== $ah) {
+ return $this->verifyBearerToken($ah);
+ }
+ if (FALSE !== $aq) {
+ return $this->verifyBearerToken($aq);
+ }
+ }
+
+ private static function _getAuthorizationHeader(array $headers)
+ {
+ $headerKeys = array_keys($headers);
+ foreach (array("X-Authorization", "Authorization") as $h) {
+ $keyPositionInArray = array_search(strtolower($h), array_map('strtolower', $headerKeys));
+ if (FALSE === $keyPositionInArray) {
+ continue;
+ }
+
+ return $headers[$headerKeys[$keyPositionInArray]];
+ }
+
+ return FALSE;
+ }
+
+ private static function _getTokenFromHeader($authorizationHeader)
+ {
+ if (0 !== strpos($authorizationHeader, "Bearer ")) {
+ return FALSE;
+ }
+
+ return substr($authorizationHeader, 7);
+ }
+
+ private static function _getTokenFromQuery(array $queryParameters)
+ {
+ if (!isset($queryParameters) || empty($queryParameters['access_token'])) {
+ return FALSE;
+ }
+
+ return $queryParameters['access_token'];
+ }
+
+ public function verifyBearerToken($token)
+ {
+ // b64token = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
+ if ( 1 !== preg_match('|^[[:alpha:][:digit:]-._~+/]+=*$|', $token)) {
+ throw new RemoteResourceServerException("invalid_token", "the access token is not a valid b64token");
+ }
+
+ $introspectionEndpoint = $this->_getConfigParameter("introspectionEndpoint");
+ $get = array("token" => $token);
+
+ if (!function_exists("curl_init")) {
+ throw new RemoteResourceServerException("internal_server_error", "php curl module not available");
+ }
+
+ $curlChannel = curl_init();
+ if (FALSE === $curlChannel) {
+ throw new RemoteResourceServerException("internal_server_error", "unable to initialize curl");
+ }
+
+ if (0 !== strpos($introspectionEndpoint, "file://")) {
+ $separator = (FALSE === strpos($introspectionEndpoint, "?")) ? "?" : "&";
+ $introspectionEndpoint .= $separator . http_build_query($get);
+ } else {
+ // file cannot have query parameter, use accesstoken as JSON file instead
+ $introspectionEndpoint .= $token . ".json";
+ }
+ if (FALSE === curl_setopt_array($curlChannel, array (
+ CURLOPT_URL => $introspectionEndpoint,
+ //CURLOPT_FOLLOWLOCATION => 1,
+ CURLOPT_RETURNTRANSFER => 1,
+ CURLOPT_SSL_VERIFYPEER => 1,
+ CURLOPT_SSL_VERIFYHOST => 2,
+ ))) {
+ throw new RemoteResourceServerException("internal_server_error", "unable to set curl options");
+ }
+
+ $output = curl_exec($curlChannel);
+
+ if (FALSE === $output) {
+ $error = curl_error($curlChannel);
+ throw new RemoteResourceServerException("internal_server_error", "unable to contact introspection endpoint");
+ }
+
+ $httpCode = curl_getinfo($curlChannel, CURLINFO_HTTP_CODE);
+ curl_close($curlChannel);
+
+ if (0 !== strpos($introspectionEndpoint, "file://")) {
+ // not a file
+ if (200 !== $httpCode) {
+ throw new RemoteResourceServerException("internal_server_error", "unexpected response code from introspection endpoint");
+ }
+ }
+
+ $data = json_decode($output, TRUE);
+ $jsonError = json_last_error();
+ if (JSON_ERROR_NONE !== $jsonError) {
+ throw new RemoteResourceServerException("internal_server_error", "unable to decode response from introspection endpoint");
+ }
+ if (!is_array($data) || !isset($data['active']) || !is_bool($data['active'])) {
+ throw new RemoteResourceServerException("internal_server_error", "unexpected response from introspection endpoint");
+ }
+
+ if (!$data['active']) {
+ throw new RemoteResourceServerException("invalid_token", "the token is not active");
+ }
+
+ return new TokenIntrospection($data);
+ }
+
+ private function _getConfigParameter($key, $required = TRUE, $default = NULL)
+ {
+ if (!array_key_exists($key, $this->_config)) {
+ if ($required) {
+ throw new RemoteResourceServerException("internal_server_error", "missing required configuration parameter");
+ } else {
+ return $default;
+ }
+ }
+
+ return $this->_config[$key];
+ }
+}
+
+class TokenIntrospection
+{
+ private $_response;
+
+ public function __construct(array $response)
+ {
+ if (!isset($response['active']) || !is_bool($response['active'])) {
+ throw new RemoteResourceServerException("internal_server_error", "active key should be set and its value a boolean");
+ }
+
+ if (isset($response['exp']) && (!is_int($response['exp']) || 0 > $response['exp'])) {
+ throw new RemoteResourceServerException("internal_server_error", "exp value must be positive integer");
+ }
+
+ if (isset($response['exp']) && (!is_int($response['iat']) || 0 > $response['iat'])) {
+ throw new RemoteResourceServerException("internal_server_error", "iat value must be positive integer");
+ }
+
+ if (isset($response['iat'])) {
+ if (time() < $response['iat']) {
+ throw new RemoteResourceServerException("internal_server_error", "token issued in the future");
+ }
+ }
+
+ if (isset($response['exp']) && isset($response['iat'])) {
+ if ($response['exp'] < $response['iat']) {
+ throw new RemoteResourceServerException("internal_server_error", "token expired before it was issued");
+ }
+ }
+
+ if (isset($response['exp'])) {
+ if (time() > $response['exp']) {
+ throw new RemoteResourceServerException("invalid_token", "the token expired");
+ }
+ }
+
+ if (isset($response['x-entitlement']) && !is_array($response['x-entitlement'])) {
+ throw new RemoteResourceServerException("internal_server_error", "x-entitlement value must be array");
+ }
+
+ $this->_response = $response;
+ }
+
+ /**
+ * REQUIRED. Boolean indicator of whether or not the presented
+ * token is currently active.
+ */
+ public function getActive()
+ {
+ return $this->_response['active'];
+ }
+
+ /**
+ * OPTIONAL. Integer timestamp, measured in the number of
+ * seconds since January 1 1970 UTC, indicating when this token will
+ * expire.
+ */
+ public function getExpiresAt()
+ {
+ return $this->_getKeyValue('exp');
+ }
+
+ /**
+ * OPTIONAL. Integer timestamp, measured in the number of
+ * seconds since January 1 1970 UTC, indicating when this token was
+ * originally issued.
+ */
+ public function getIssuedAt()
+ {
+ return $this->_getKeyValue('iat');
+ }
+
+ /**
+ * OPTIONAL. A space-separated list of strings representing the
+ * scopes associated with this token, in the format described in
+ * Section 3.3 of OAuth 2.0 [RFC6749].
+ */
+ public function getScope()
+ {
+ return $this->_getKeyValue('scope');
+ }
+
+ /**
+ * OPTIONAL. Client Identifier for the OAuth Client that
+ * requested this token.
+ */
+ public function getClientId()
+ {
+ return $this->_getKeyValue('client_id');
+ }
+
+ /**
+ * OPTIONAL. Local identifier of the Resource Owner who authorized
+ * this token.
+ */
+ public function getSub()
+ {
+ return $this->_getKeyValue('sub');
+ }
+
+ /**
+ * OPTIONAL. Service-specific string identifier or list of string
+ * identifiers representing the intended audience for this token.
+ */
+ public function getAud()
+ {
+ return $this->_getKeyValue('aud');
+ }
+
+ /**
+ * OPTIONAL. Type of the token as defined in OAuth 2.0
+ * section 5.1.
+ */
+ public function getTokenType()
+ {
+ return $this->_getKeyValue('token_type');
+ }
+
+ private function _getKeyValue($key)
+ {
+ return isset($this->_response[$key]) ? $this->_response[$key] : FALSE;
+ }
+
+ /* ADDITIONAL HELPER METHODS */
+ public function getResourceOwnerId()
+ {
+ return $this->getSub();
+ }
+
+ public function getScopeAsArray()
+ {
+ return FALSE !== $this->getScope() ? explode(" ", $this->getScope()) : FALSE;
+ }
+
+ public function hasScope($scope)
+ {
+ return FALSE !== $this->getScopeAsArray() ? in_array($scope, $this->getScopeAsArray()) : FALSE;
+ }
+
+ public function requireScope($scope)
+ {
+ if (FALSE === $this->hasScope($scope)) {
+ throw new RemoteResourceServerException("insufficient_scope", "no permission for this call with granted scope");
+ }
+ }
+
+ public function requireAnyScope(array $scope)
+ {
+ if (FALSE === $this->hasAnyScope($scope)) {
+ throw new RemoteResourceServerException("insufficient_scope", "no permission for this call with granted scope");
+ }
+ }
+
+ /**
+ * At least one of the scopes should be granted.
+ *
+ * @param array $scope the list of scopes of which one should be granted
+ * @return TRUE when at least one of the requested scopes was granted,
+ * FALSE when none were granted.
+ */
+ public function hasAnyScope(array $scope)
+ {
+ foreach ($scope as $s) {
+ if ($this->hasScope($s)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ public function getEntitlement()
+ {
+ return $this->_getKeyValue('x-entitlement');
+ }
+
+ public function hasEntitlement($entitlement)
+ {
+ return FALSE !== $this->getEntitlement() ? in_array($entitlement, $this->getEntitlement()) : FALSE;
+ }
+
+ public function requireEntitlement($entitlement)
+ {
+ if (FALSE === $this->hasEntitlement($entitlement)) {
+ throw new RemoteResourceServerException("insufficient_entitlement", "no permission for this call with granted entitlement");
+ }
+ }
+
+ public function getExt()
+ {
+ return $this->_getKeyValue('x-ext');
+ }
+
+}
+
+class RemoteResourceServerException extends \Exception
+{
+ private $description;
+ private $responseCode;
+ private $realm;
+
+ public function __construct($message, $description, $code = 0, Exception $previous = null)
+ {
+ switch ($message) {
+ case "no_token":
+ case "invalid_token":
+ $this->responseCode = 401;
+ break;
+ case "insufficient_scope":
+ case "insufficient_entitlement":
+ $this->responseCode = 403;
+ break;
+ case "internal_server_error":
+ $this->responseCode = 500;
+ break;
+ case "invalid_request":
+ default:
+ $this->responseCode = 400;
+ break;
+ }
+
+ $this->description = $description;
+ $this->realm = "Resource Server";
+
+ parent::__construct($message, $code, $previous);
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function setRealm($resourceServerRealm)
+ {
+ $this->realm = (is_string($resourceServerRealm) && !empty($resourceServerRealm)) ? $resourceServerRealm : "Resource Server";
+ }
+
+ public function getResponseCode()
+ {
+ return $this->responseCode;
+ }
+
+ public function getAuthenticateHeader()
+ {
+ $authenticateHeader = NULL;
+ if (500 !== $this->responseCode) {
+ if ("no_token" === $this->message) {
+ // no authorization header is a special case, the client did not know
+ // authentication was required, so tell it now without giving error message
+ $authenticateHeader = sprintf('Bearer realm="%s"', $this->realm);
+ } else {
+ $authenticateHeader = sprintf('Bearer realm="%s",error="%s",error_description="%s"', $this->realm, $this->message, $this->description);
+ }
+ }
+
+ return $authenticateHeader;
+ }
+
+ public function getContent()
+ {
+ return json_encode(array("error" => $this->message, "error_description" => $this->description));
+ }
+
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/RemoteResourceServerTest.php b/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/RemoteResourceServerTest.php
new file mode 100644
index 000000000..b4041abaa
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/RemoteResourceServerTest.php
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "OAuth" . DIRECTORY_SEPARATOR . "RemoteResourceServer.php";
+
+use \OAuth\RemoteResourceServer as RemoteResourceServer;
+use \OAuth\RemoteResourceServerException as RemoteResourceServerException;
+
+class RemoteResourceServerTest extends PHPUnit_Framework_TestCase
+{
+
+ private $_dataPath;
+
+ public function setUp()
+ {
+ $this->_dataPath = "file://" . dirname(__DIR__) . DIRECTORY_SEPARATOR . "data/";
+ }
+
+ public function testBasicToken()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array("Authorization" => "Bearer 001"), array());
+ $this->assertEquals("fkooman", $introspection->getSub());
+ $this->assertEquals("testclient", $introspection->getClientId());
+ $this->assertEquals(2366377846, $introspection->getExpiresAt());
+ $this->assertEquals(1366376612, $introspection->getIssuedAt());
+ $this->assertEquals("foo bar", $introspection->getScope());
+ $this->assertEquals(array("urn:x-foo:service:access","urn:x-bar:privilege:admin"), $introspection->getEntitlement());
+ $this->assertTrue($introspection->getActive());
+ }
+
+ public function testBasicTokenNoEntitlement()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array(), array("access_token" => "002"));
+ $this->assertEquals("frko", $introspection->getSub());
+ $this->assertEquals("testclient", $introspection->getClientId());
+ $this->assertEquals(2366377846, $introspection->getExpiresAt());
+ $this->assertEquals(1366376612, $introspection->getIssuedAt());
+ $this->assertEquals("a b c", $introspection->getScope());
+ $this->assertFalse($introspection->getEntitlement());
+ $this->assertTrue($introspection->getActive());
+ }
+
+ public function testInvalidToken()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array(), array("access_token" => "003"));
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ $this->assertEquals("invalid_token", $e->getMessage());
+ $this->assertEquals("the token is not active", $e->getDescription());
+ $this->assertEquals(401, $e->getResponseCode());
+ $this->assertEquals('Bearer realm="Resource Server",error="invalid_token",error_description="the token is not active"', $e->getAuthenticateHeader());
+ }
+ }
+
+ public function testInvalidIntrospectionResponse()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array("Authorization" => "Bearer 100"), array());
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ $this->assertEquals("internal_server_error", $e->getMessage());
+ $this->assertEquals("unexpected response from introspection endpoint", $e->getDescription());
+ $this->assertEquals(500, $e->getResponseCode());
+ $this->assertNull($e->getAuthenticateHeader());
+ }
+ }
+
+ public function testNoJsonResponse()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array("Authorization" => "Bearer 101"), array());
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ $this->assertEquals("internal_server_error", $e->getMessage());
+ $this->assertEquals("unable to decode response from introspection endpoint", $e->getDescription());
+ $this->assertEquals(500, $e->getResponseCode());
+ $this->assertNull($e->getAuthenticateHeader());
+ }
+ }
+
+ public function testMultipleBearerTokens()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array("Authorization" => "Bearer 003"), array("access_token" => "003"));
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ $this->assertEquals("invalid_request", $e->getMessage());
+ $this->assertEquals("more than one method for including an access token used", $e->getDescription());
+ $this->assertEquals(400, $e->getResponseCode());
+ $this->assertEquals('Bearer realm="Resource Server",error="invalid_request",error_description="more than one method for including an access token used"', $e->getAuthenticateHeader());
+ }
+ }
+
+ public function testExt()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array("Authorization" => "Bearer 004"), array());
+ $this->assertTrue($introspection->getActive());
+ $this->assertEquals(array("uid" => array("admin"), "schacHomeOrganization" => array("localhost")), $introspection->getExt());
+ }
+
+ public function testNoBearerTokens()
+ {
+ $config = array(
+ "introspectionEndpoint" => $this->_dataPath,
+ );
+ try {
+ $rs = new RemoteResourceServer($config);
+ $introspection = $rs->verifyRequest(array(), array());
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ $this->assertEquals("no_token", $e->getMessage());
+ $this->assertEquals("missing token", $e->getDescription());
+ $this->assertEquals(401, $e->getResponseCode());
+ $this->assertEquals('Bearer realm="Resource Server"', $e->getAuthenticateHeader());
+ }
+ }
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/TokenIntrospectionTest.php b/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/TokenIntrospectionTest.php
new file mode 100644
index 000000000..e0e274eb0
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/OAuth/TokenIntrospectionTest.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "OAuth" . DIRECTORY_SEPARATOR . "RemoteResourceServer.php";
+
+use \OAuth\TokenIntrospection as TokenIntrospection;
+use \OAuth\RemoteResourceServerException as RemoteResourceServerException;
+
+class TokenIntrospectionTest extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @dataProvider validTokenProvider
+ */
+ public function testTokenIntrospectionTest($token, $active, $expiresAt, $issuedAt, $scope, $entitlement, $clientId, $sub, $aud)
+ {
+ $i = new TokenIntrospection($token);
+ $this->assertEquals($active, $i->getActive());
+ $this->assertEquals($expiresAt, $i->getExpiresAt());
+ $this->assertEquals($issuedAt, $i->getIssuedAt());
+ $this->assertEquals($scope, $i->getScope());
+ if (FALSE !== $i->getScope()) {
+ $eScope = explode(" ", $i->getScope());
+ $this->assertEquals($eScope, $i->getScopeAsArray());
+ for ( $j = 0; $j < count($eScope); $j++) {
+ $this->assertTrue($i->hasScope($eScope[$j]));
+ $this->assertTrue($i->hasAnyScope(array($eScope[$j], "bogus")));
+ $i->requireScope($eScope[$j]);
+ }
+ }
+ $e = $i->getEntitlement();
+ if (FALSE !== $e) {
+ for ( $j = 0; $j < count($e); $j++) {
+ $this->assertTrue($i->hasEntitlement($e[$j]));
+ $i->requireEntitlement($e[$j]);
+ }
+ }
+ $this->assertEquals($clientId, $i->getClientId());
+ $this->assertEquals($sub, $i->getResourceOwnerId());
+ $this->assertEquals($sub, $i->getSub());
+ $this->assertEquals($aud, $i->getAud());
+ try {
+ $i->requireScope("bogus");
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ }
+ try {
+ $i->requireEntitlement("bogus");
+ $this->assertTrue(FALSE);
+ } catch (RemoteResourceServerException $e) {
+ }
+
+ $this->assertFalse($i->hasAnyScope(array("foo")));
+ }
+
+ public function validTokenProvider()
+ {
+ $iat = time();
+ $exp = $iat + 100;
+
+ return array(
+ array(
+ array("active" => TRUE),
+ TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
+ ),
+
+ array(
+ array("active" => TRUE, "exp" => $exp, "iat" => $iat, "scope" => "read write", "client_id" => "foo", "sub" => "fkooman", "aud" => "foobar"),
+ TRUE, $exp, $iat, "read write", FALSE, "foo", "fkooman", "foobar"
+ ),
+
+ array(
+ array("active" => TRUE, "exp" => $exp, "iat" => $iat, "scope" => "read write", "x-entitlement" => array("manager", "owner", "user"), "client_id" => "foo", "sub" => "fkooman", "aud" => "foobar"),
+ TRUE, $exp, $iat, "read write", array("manager", "owner", "user"), "foo", "fkooman", "foobar"
+ ),
+ );
+ }
+
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/001.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/001.json
new file mode 100644
index 000000000..f844946a5
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/001.json
@@ -0,0 +1,12 @@
+{
+ "active": true,
+ "client_id": "testclient",
+ "exp": 2366377846,
+ "iat": 1366376612,
+ "scope": "foo bar",
+ "sub": "fkooman",
+ "x-entitlement": [
+ "urn:x-foo:service:access",
+ "urn:x-bar:privilege:admin"
+ ]
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/002.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/002.json
new file mode 100644
index 000000000..a45f9ccee
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/002.json
@@ -0,0 +1,8 @@
+{
+ "active": true,
+ "client_id": "testclient",
+ "exp": 2366377846,
+ "iat": 1366376612,
+ "scope": "a b c",
+ "sub": "frko"
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/003.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/003.json
new file mode 100644
index 000000000..bba306789
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/003.json
@@ -0,0 +1,3 @@
+{
+ "active": false
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/004.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/004.json
new file mode 100644
index 000000000..a1b9abf4f
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/004.json
@@ -0,0 +1,19 @@
+{
+ "active": true,
+ "client_id": "html-manage-authorizations",
+ "exp": 2366844432,
+ "iat": 1366815632,
+ "scope": "authorizations",
+ "sub": "48a5788a56b3dc9035e981aa9c8924360c1906e4",
+ "x-entitlement": [
+ "urn:x-oauth:entitlement:applications"
+ ],
+ "x-ext": {
+ "schacHomeOrganization": [
+ "localhost"
+ ],
+ "uid": [
+ "admin"
+ ]
+ }
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/100.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/100.json
new file mode 100644
index 000000000..357d63809
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/100.json
@@ -0,0 +1,3 @@
+{
+ "invalid-format": false
+}
diff --git a/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/101.json b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/101.json
new file mode 100644
index 000000000..6089c5d95
--- /dev/null
+++ b/user_oauth/3rdparty/php-oauth-lib-rs/tests/data/101.json
@@ -0,0 +1 @@
+NO JSON
diff --git a/user_oauth/README.md b/user_oauth/README.md
index 08b703d49..43b007fa4 100644
--- a/user_oauth/README.md
+++ b/user_oauth/README.md
@@ -1,19 +1,21 @@
# Introduction
-This version implements the server side OAuth "Bearer" token verification
-against an external authorization server. It aims at supporting both
-the [php-oauth](https://github.com/fkooman/php-oauth) service and the
-[Google](https://developers.google.com/accounts/docs/OAuth2Login#validatingtoken) service.
+This app implements server side OAuth 2.0 "Bearer" token verification against
+an external authorization server. It aims at supporting the
+[php-oauth](https://github.com/fkooman/php-oauth) service. However, any other
+OAuth 2.0 AS supporting `draft-richer-oauth-introspection` should work.
# Requirements
* PHP cURL extension
* Apache (because we use `apache_request_headers()` at the moment)
# Installation
-Install this code in the directory `user_oauth` in the `apps` directory of
-your Owncloud installation.
+Install this code in the directory `user_oauth` in the `apps` directory of your
+ownCloud installation.
-This module needs an external dependency to verify the OAuth tokens at the
-OAuth authorization server. A script can be used to install this dependency:
+This module needs an external library to verify the OAuth tokens at the OAuth
+authorization server. A script can be used to install this dependency, by
+default is in included in the `3rdparty` directory. So you only need this if
+you want to download the library again or update it.
$ cd /path/to/owncloud/apps/user_oauth
$ cd 3rdparty
@@ -21,53 +23,43 @@ OAuth authorization server. A script can be used to install this dependency:
You need Git installed on your server to fetch the 3rd party dependency.
-You can enable the `user_oauth` app after login with the `admin` account. Go
-to `Settings`, then `Apps` and finally select the `OAuth` module from the list
-of modules, select it and press the `Enable` button.
+You can enable the `user_oauth` app after login with the `admin` account. Go to
+`Settings`, then `Apps` and finally select the `OAuth` module from the list of
+modules, select it and press the `Enable` button.
# Configuration
-There currently is only one configuration parameter: the Token Info Endpoint.
-For quick tests, one can use the playground environment, installed using
-[this](https://github.com/fkooman/oauth-install-all) script located at
-https://frko.surfnetlabs.nl/workshop/.
+There currently is only one configuration parameter: the introspection
+endpoint. For quick tests, you can use the playground environment, installed
+using [this](https://github.com/fkooman/oauth-install-all) script located at
+https://frko.surfnetlabs.nl/workshop/.
-For the "workshop" installation the Token Info Endpoint would be
+For the "workshop" installation the introspection endpoint would be:
- https://frko.surfnetlabs.nl/workshop/php-oauth/tokeninfo.php
-
-For Google the Token Info Endpoint is:
-
- https://www.googleapis.com/oauth2/v1/tokeninfo
+ https://frko.surfnetlabs.nl/workshop/php-oauth/introspect.php
You can set this endpoint by going to `Settings`, then `Admin` and then under
the section head `OAuth` configure the URL.
# Applications
An application needs to use the OAuth service to retrieve an access token to
-use this with the OAuth enabled WebDAV endpoint. The endpoint, assuming you
-run the service on https://www.example.org/owncloud, note `odav` instead of
+use this with the OAuth enabled WebDAV endpoint. The endpoint, assuming you run
+the service on https://www.example.org/owncloud, note `odav` instead of
`webdav`:
https://www.example.org/owncloud/remote.php/odav/<FILE.EXT>
-So, in order for an application to work it needs to obtain an access token
-from the OAuth authorization server that you configured as a Token Info
-Endpoint in the OAuth app configuration in Owncloud. If you used the
-playground mentioned above that would mean using the following URLs:
+So, in order for an application to work it needs to obtain an access token from
+the OAuth authorization server that you configured as an introspection endpoint
+in the OAuth app configuration in ownCloud. If you used the playground
+mentioned above that would mean using the following URLs for authorization and
+token endpoints:
https://frko.surfnetlabs.nl/workshop/php-oauth/authorize.php
https://frko.surfnetlabs.nl/workshop/php-oauth/token.php
-For Google this will probably be some Google URL. You also need to register the
-app at Google. In the playground environment you can also register an OAuth
-client yourself.
-
-Template applications for both
-[Android](https://github.com/OpenConextApps/android-oauth-app) and
-[iOS](https://github.com/OpenConextApps/ios-oauth-app) are available that
-implement OAuth 2.0 and can be used to modify the Owncloud Mobile Apps.
-
-So far, the Owncloud Mobile Apps have not been updated to support OAuth 2.0.
+It seems the Android app of ownCloud should support OAuth at the server, but so
+far we were unable to make it work. We tested version 1.4.1 of the Android app
+from the F-Droid repository.
# Compatibilty
-The app was tested with version 5 of Owncloud.
+The app was tested with version 5 of ownCloud.
diff --git a/user_oauth/ajax/seturl.php b/user_oauth/ajax/seturl.php
index 2f3428766..41cf361dd 100644
--- a/user_oauth/ajax/seturl.php
+++ b/user_oauth/ajax/seturl.php
@@ -9,6 +9,6 @@
OCP\User::checkAdminUser();
OCP\JSON::callCheck();
-OCP\Config::setSystemValue( 'tokenInfoEndpoint', $_POST['tokenInfoEndpoint'] );
+OCP\Config::setSystemValue( 'introspectionEndpoint', $_POST['introspectionEndpoint'] );
echo 'true';
diff --git a/user_oauth/appinfo/version b/user_oauth/appinfo/version
index 5625e59da..7e32cd569 100644
--- a/user_oauth/appinfo/version
+++ b/user_oauth/appinfo/version
@@ -1 +1 @@
-1.2
+1.3
diff --git a/user_oauth/js/admin.js b/user_oauth/js/admin.js
index 1456c22e7..7cb8f4fd7 100644
--- a/user_oauth/js/admin.js
+++ b/user_oauth/js/admin.js
@@ -2,9 +2,9 @@ $(document).ready(function(){
- $('#tokenInfoEndpoint').blur(function(event){
+ $('#introspectionEndpoint').blur(function(event){
event.preventDefault();
- var post = $( "#tokenInfoEndpoint" ).serialize();
+ var post = $( "#introspectionEndpoint" ).serialize();
$.post( OC.filePath('user_oauth', 'ajax', 'seturl.php') , post, function(data){
$('#user_oauth .msg').text('Finished saving: ' + data);
});
diff --git a/user_oauth/oauth.php b/user_oauth/oauth.php
index 0015df6bc..f5f0133d9 100644
--- a/user_oauth/oauth.php
+++ b/user_oauth/oauth.php
@@ -1,6 +1,6 @@
<?php
-require_once '3rdparty/php-lib-remote-rs/lib/OAuth/RemoteResourceServer.php';
+require_once '3rdparty/php-oauth-lib-rs/lib/OAuth/RemoteResourceServer.php';
use \OAuth\RemoteResourceServer as RemoteResourceServer;
use \OAuth\RemoteResourceServerException as RemoteResourceServerException;
@@ -8,15 +8,12 @@ use \OAuth\RemoteResourceServerException as RemoteResourceServerException;
class OC_Connector_Sabre_OAuth implements Sabre_DAV_Auth_IBackend
{
private $currentUser;
- private $tokenInfoEndpoint;
- private $useResourceOwnerId;
- private $userIdAttributeName;
+ private $introspectionEndpoint;
- public function __construct($tokenInfoEndpoint, $useResourceOwnerId = TRUE, $userIdAttributeName = "uid")
+ public function __construct($introspectionEndpoint)
{
- $this->tokenInfoEndpoint = $tokenInfoEndpoint;
- $this->useResourceOwnerId = $useResourceOwnerId;
- $this->userIdAttributeName = $userIdAttributeName;
+ $this->introspectionEndpoint = $introspectionEndpoint;
+ $this->currentUser = null;
}
public function getCurrentUser()
@@ -27,42 +24,34 @@ class OC_Connector_Sabre_OAuth implements Sabre_DAV_Auth_IBackend
public function authenticate(Sabre_DAV_Server $server, $realm)
{
$config = array(
- "tokenInfoEndpoint" => $this->tokenInfoEndpoint,
- "throwException" => TRUE,
- "resourceServerRealm" => $realm,
+ "introspectionEndpoint" => $this->introspectionEndpoint,
+ "realm" => $realm
);
try {
$resourceServer = new RemoteResourceServer($config);
-
- $resourceServer->verifyRequest();
-
- if ($this->useResourceOwnerId) {
- // when using the user_id
- $this->currentUser = $resourceServer->getResourceOwnerId();
- } else {
- // when using a (SAML) attribute
- $attributes = $resourceServer->getAttributes();
- $this->currentUser = $attributes[$this->userIdAttributeName][0];
- }
+ $tokenIntrospection = $resourceServer->verifyRequest(apache_request_headers(), $_GET);
+ $this->currentUser = $tokenIntrospection->getSub();
OC_User::setUserid($this->currentUser);
OC_Util::setupFS($this->currentUser);
return true;
-
} catch (RemoteResourceServerException $e) {
- $server->httpResponse->setHeader('WWW-Authenticate', $e->getAuthenticateHeader());
-
- // FIXME: do we need to set the status here explicitly, or does the
- // Exception below take care of this?
- $server->httpResponse->sendStatus($e->getResponseCode());
- if ("403" === $e->getResponseCode()) {
- throw new Sabre_DAV_Exception_Forbidden($e->getDescription());
- } else {
- throw new Sabre_DAV_Exception_NotAuthenticated($e->getDescription());
+ switch ($e->getMessage()) {
+ case "insufficient_entitlement":
+ case "insufficient_scope":
+ $server->httpResponse->setHeader('WWW-Authenticate', $e->getAuthenticateHeader());
+ throw new Sabre_DAV_Exception_Forbidden($e->getDescription());
+ case "invalid_request":
+ throw new Sabre_DAV_Exception_NotAuthenticated($e->getDescription());
+ case "invalid_token":
+ case "no_token":
+ $server->httpResponse->setHeader('WWW-Authenticate', $e->getAuthenticateHeader());
+ throw new Sabre_DAV_Exception_NotAuthenticated($e->getDescription());
+ case "internal_server_error":
+ throw new Sabre_DAV_Exception($e->getDescription());
}
}
}
-
}
diff --git a/user_oauth/remote.php b/user_oauth/remote.php
index 7b6920619..94b20937a 100644
--- a/user_oauth/remote.php
+++ b/user_oauth/remote.php
@@ -26,14 +26,12 @@
$RUNTIME_APPTYPES=array('filesystem','authentication');
OC_App::loadApps($RUNTIME_APPTYPES);
-$tokenInfoEndpoint = \OC_Config::getValue( "tokenInfoEndpoint", "https://www.googleapis.com/oauth2/v1/tokeninfo" );
-$useResourceOwnerId = TRUE; // FIXME: take this from configuration instead
-$userIdAttributeName = "uid"; // FIXME: take this from configuration instead
+$introspectionEndpoint = \OC_Config::getValue( "introspectionEndpoint", "https://frko.surfnetlabs.nl/workshop/php-oauth/introspect.php" );
require_once 'oauth.php';
// Backends
-$authBackend = new OC_Connector_Sabre_OAuth($tokenInfoEndpoint, $useResourceOwnerId, $userIdAttributeName);
+$authBackend = new OC_Connector_Sabre_OAuth($introspectionEndpoint);
$lockBackend = new OC_Connector_Sabre_Locks();
$requestBackend = new OC_Connector_Sabre_Request();
diff --git a/user_oauth/settings.php b/user_oauth/settings.php
index 077caae11..04ce8a110 100644
--- a/user_oauth/settings.php
+++ b/user_oauth/settings.php
@@ -6,6 +6,6 @@ OCP\Util::addScript( "user_oauth", "admin" );
$tmpl = new OCP\Template( 'user_oauth', 'settings');
-$tmpl->assign('tokenInfoEndpoint', OCP\Config::getSystemValue( "tokenInfoEndpoint", 'https://www.googleapis.com/oauth2/v1/tokeninfo' ));
+$tmpl->assign('introspectionEndpoint', OCP\Config::getSystemValue( "introspectionEndpoint", 'https://frko.surfnetlabs.nl/workshop/php-oauth/introspect.php' ));
return $tmpl->fetchPage();
diff --git a/user_oauth/templates/settings.php b/user_oauth/templates/settings.php
index 37ee75a4a..f3ff68cd7 100644
--- a/user_oauth/templates/settings.php
+++ b/user_oauth/templates/settings.php
@@ -1,8 +1,8 @@
<form id="user_oauth">
<fieldset class="personalblock">
<strong>OAuth</strong><br />
- <input type="text" name="tokenInfoEndpoint" id="tokenInfoEndpoint" value="<?php p($_['tokenInfoEndpoint']); ?>" placeholder="<?php p($l->t('Token Info Endpoint'));?>" />
+ <input type="text" name="introspectionEndpoint" id="introspectionEndpoint" value="<?php p($_['introspectionEndpoint']); ?>" placeholder="<?php p($l->t('Introspection endpoint'));?>" />
<br />
- <span class="msg">Provide the OAuth Authorization Server Token Info Endpoint here.</span>
+ <span class="msg">Provide the OAuth 2.0 Authorization Server introspection endpoint here.</span>
</fieldset>
</form>