aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php')
-rw-r--r--vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php226
1 files changed, 226 insertions, 0 deletions
diff --git a/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
new file mode 100644
index 000000000..bb11a6954
--- /dev/null
+++ b/vendor/bshaffer/oauth2-server-php/src/OAuth2/GrantType/JwtBearer.php
@@ -0,0 +1,226 @@
+<?php
+
+namespace OAuth2\GrantType;
+
+use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
+use OAuth2\Storage\JwtBearerInterface;
+use OAuth2\Encryption\Jwt;
+use OAuth2\Encryption\EncryptionInterface;
+use OAuth2\ResponseType\AccessTokenInterface;
+use OAuth2\RequestInterface;
+use OAuth2\ResponseInterface;
+
+/**
+ * The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4
+ *
+ * @author F21
+ * @author Brent Shaffer <bshafs at gmail dot com>
+ */
+class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
+{
+ private $jwt;
+
+ protected $storage;
+ protected $audience;
+ protected $jwtUtil;
+ protected $allowedAlgorithms;
+
+ /**
+ * Creates an instance of the JWT bearer grant type.
+ *
+ * @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
+ * @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
+ * @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
+ * @param array $config
+ */
+ public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
+ {
+ $this->storage = $storage;
+ $this->audience = $audience;
+
+ if (is_null($jwtUtil)) {
+ $jwtUtil = new Jwt();
+ }
+
+ $this->config = array_merge(array(
+ 'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
+ ), $config);
+
+ $this->jwtUtil = $jwtUtil;
+
+ $this->allowedAlgorithms = $this->config['allowed_algorithms'];
+ }
+
+ /**
+ * Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
+ *
+ * @return
+ * The string identifier for grant_type.
+ *
+ * @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier()
+ */
+ public function getQuerystringIdentifier()
+ {
+ return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
+ }
+
+ /**
+ * Validates the data from the decoded JWT.
+ *
+ * @return
+ * TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.
+ *
+ * @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
+ */
+ public function validateRequest(RequestInterface $request, ResponseInterface $response)
+ {
+ if (!$request->request("assertion")) {
+ $response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required');
+
+ return null;
+ }
+
+ // Store the undecoded JWT for later use
+ $undecodedJWT = $request->request('assertion');
+
+ // Decode the JWT
+ $jwt = $this->jwtUtil->decode($request->request('assertion'), null, false);
+
+ if (!$jwt) {
+ $response->setError(400, 'invalid_request', "JWT is malformed");
+
+ return null;
+ }
+
+ // ensure these properties contain a value
+ // @todo: throw malformed error for missing properties
+ $jwt = array_merge(array(
+ 'scope' => null,
+ 'iss' => null,
+ 'sub' => null,
+ 'aud' => null,
+ 'exp' => null,
+ 'nbf' => null,
+ 'iat' => null,
+ 'jti' => null,
+ 'typ' => null,
+ ), $jwt);
+
+ if (!isset($jwt['iss'])) {
+ $response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided");
+
+ return null;
+ }
+
+ if (!isset($jwt['sub'])) {
+ $response->setError(400, 'invalid_grant', "Invalid subject (sub) provided");
+
+ return null;
+ }
+
+ if (!isset($jwt['exp'])) {
+ $response->setError(400, 'invalid_grant', "Expiration (exp) time must be present");
+
+ return null;
+ }
+
+ // Check expiration
+ if (ctype_digit($jwt['exp'])) {
+ if ($jwt['exp'] <= time()) {
+ $response->setError(400, 'invalid_grant', "JWT has expired");
+
+ return null;
+ }
+ } else {
+ $response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp");
+
+ return null;
+ }
+
+ // Check the not before time
+ if ($notBefore = $jwt['nbf']) {
+ if (ctype_digit($notBefore)) {
+ if ($notBefore > time()) {
+ $response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time");
+
+ return null;
+ }
+ } else {
+ $response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp");
+
+ return null;
+ }
+ }
+
+ // Check the audience if required to match
+ if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) {
+ $response->setError(400, 'invalid_grant', "Invalid audience (aud)");
+
+ return null;
+ }
+
+ // Check the jti (nonce)
+ // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7
+ if (isset($jwt['jti'])) {
+ $jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
+
+ //Reject if jti is used and jwt is still valid (exp parameter has not expired).
+ if ($jti && $jti['expires'] > time()) {
+ $response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used");
+
+ return null;
+ } else {
+ $this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']);
+ }
+ }
+
+ // Get the iss's public key
+ // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1
+ if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) {
+ $response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided");
+
+ return null;
+ }
+
+ // Verify the JWT
+ if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) {
+ $response->setError(400, 'invalid_grant', "JWT failed signature verification");
+
+ return null;
+ }
+
+ $this->jwt = $jwt;
+
+ return true;
+ }
+
+ public function getClientId()
+ {
+ return $this->jwt['iss'];
+ }
+
+ public function getUserId()
+ {
+ return $this->jwt['sub'];
+ }
+
+ public function getScope()
+ {
+ return null;
+ }
+
+ /**
+ * Creates an access token that is NOT associated with a refresh token.
+ * If a subject (sub) the name of the user/account we are accessing data on behalf of.
+ *
+ * @see OAuth2\GrantType\GrantTypeInterface::createAccessToken()
+ */
+ public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
+ {
+ $includeRefreshToken = false;
+
+ return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken);
+ }
+}