1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22 23declare(strict_types=0); 24 25namespace Ampache\Module\Util\OAuth; 26 27use Ampache\Module\Util\OAuth\Exception\OAuthException; 28 29/** 30 * Class OAuthServer 31 * 32 * @deprecated Not in use 33 */ 34class OAuthServer 35{ 36 protected $timestamp_threshold = 300; // in seconds, five minutes 37 protected $version = '1.0'; 38 protected $signature_methods = array(); 39 40 protected $data_store; 41 42 /** 43 * OAuthServer constructor. 44 * @param $data_store 45 */ 46 public function __construct($data_store) 47 { 48 $this->data_store = $data_store; 49 } 50 51 /** 52 * @param $signature_method 53 */ 54 public function add_signature_method($signature_method) 55 { 56 $this->signature_methods[$signature_method->get_name()] = $signature_method; 57 } 58 59 // high level functions 60 61 /** 62 * process a request_token request 63 * returns the request token on success 64 * @param $request 65 * @return 66 * @throws OAuthException 67 */ 68 public function fetch_request_token(&$request) 69 { 70 $this->get_version($request); 71 72 $consumer = $this->get_consumer($request); 73 74 // no token required for the initial token request 75 $token = null; 76 77 $this->check_signature($request, $consumer, $token); 78 79 // Rev A change 80 $callback = $request->get_parameter('oauth_callback'); 81 82 return $this->data_store->new_request_token($consumer, $callback); 83 } 84 85 /** 86 * process an access_token request 87 * returns the access token on success 88 * @param $request 89 * @return mixed 90 * @throws OAuthException 91 */ 92 public function fetch_access_token(&$request) 93 { 94 $this->get_version($request); 95 96 $consumer = $this->get_consumer($request); 97 98 // requires authorized request token 99 $token = $this->get_token($request, $consumer, "request"); 100 101 $this->check_signature($request, $consumer, $token); 102 103 // Rev A change 104 $verifier = $request->get_parameter('oauth_verifier'); 105 106 return $this->data_store->new_access_token($token, $consumer, $verifier); 107 } 108 109 /** 110 * verify an api call, checks all the parameters 111 * @param $request 112 * @return array 113 * @throws OAuthException 114 */ 115 public function verify_request(&$request) 116 { 117 $this->get_version($request); 118 $consumer = $this->get_consumer($request); 119 $token = $this->get_token($request, $consumer); 120 $this->check_signature($request, $consumer, $token); 121 122 return array($consumer, $token); 123 } 124 125 // Internals from here 126 127 /** 128 * version 1 129 * @param $request 130 * @return string 131 * @throws OAuthException 132 */ 133 private function get_version(&$request) 134 { 135 $version = $request->get_parameter("oauth_version"); 136 if (!$version) { 137 // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. 138 // Chapter 7.0 ("Accessing Protected Resources") 139 $version = '1.0'; 140 } 141 if ($version !== $this->version) { 142 throw new OAuthException("OAuth version '$version' not supported"); 143 } 144 145 return $version; 146 } 147 148 /** 149 * figure out the signature with some defaults 150 * @param $request 151 * @return mixed 152 * @throws OAuthException 153 */ 154 private function get_signature_method($request) 155 { 156 $signature_method = $request instanceof OAuthRequest ? $request->get_parameter("oauth_signature_method") : null; 157 158 if (!$signature_method) { 159 // According to chapter 7 ("Accessing Protected Resources") the signature-method 160 // parameter is required, and we can't just fallback to PLAINTEXT 161 throw new OAuthException('No signature method parameter. This parameter is required'); 162 } 163 164 if (!in_array($signature_method, array_keys($this->signature_methods))) { 165 throw new OAuthException("Signature method '$signature_method' not supported " . "try one of the following: " . implode(", ", 166 array_keys($this->signature_methods))); 167 } 168 169 return $this->signature_methods[$signature_method]; 170 } 171 172 /** 173 * try to find the consumer for the provided request's consumer key 174 * @param $request 175 * @return 176 * @throws OAuthException 177 */ 178 private function get_consumer($request) 179 { 180 $consumer_key = $request instanceof OAuthRequest ? $request->get_parameter("oauth_consumer_key") : null; 181 182 if (!$consumer_key) { 183 throw new OAuthException("Invalid consumer key"); 184 } 185 186 $consumer = $this->data_store->lookup_consumer($consumer_key); 187 if (!$consumer) { 188 throw new OAuthException("Invalid consumer"); 189 } 190 191 return $consumer; 192 } 193 194 /** 195 * try to find the token for the provided request's token key 196 * @param $request 197 * @param $consumer 198 * @param string $token_type 199 * @return 200 * @throws OAuthException 201 */ 202 private function get_token($request, $consumer, $token_type = "access") 203 { 204 $token_field = $request instanceof OAuthRequest ? $request->get_parameter('oauth_token') : null; 205 $token = $this->data_store->lookup_token($consumer, $token_type, $token_field); 206 if (!$token) { 207 throw new OAuthException("Invalid $token_type token: $token_field"); 208 } 209 210 return $token; 211 } 212 213 /** 214 * all-in-one function to check the signature on a request 215 * should guess the signature method appropriately 216 * @param $request 217 * @param $consumer 218 * @param $token 219 * @throws OAuthException 220 */ 221 private function check_signature($request, $consumer, $token) 222 { 223 // this should probably be in a different method 224 $timestamp = $request instanceof OAuthRequest ? $request->get_parameter('oauth_timestamp') : null; 225 $nonce = $request instanceof OAuthRequest ? $request->get_parameter('oauth_nonce') : null; 226 227 $this->check_timestamp($timestamp); 228 $this->check_nonce($consumer, $token, $nonce, $timestamp); 229 230 $signature_method = $this->get_signature_method($request); 231 232 $signature = $request->get_parameter('oauth_signature'); 233 $valid_sig = $signature_method->check_signature($request, $consumer, $token, $signature); 234 235 if (!$valid_sig) { 236 throw new OAuthException("Invalid signature"); 237 } 238 } 239 240 /** 241 * check that the timestamp is new enough 242 * @param $timestamp 243 * @throws OAuthException 244 */ 245 private function check_timestamp($timestamp) 246 { 247 if (!$timestamp) { 248 throw new OAuthException('Missing timestamp parameter. The parameter is required'); 249 } 250 251 // verify that timestamp is recent 252 $now = time(); 253 if (abs($now - $timestamp) > $this->timestamp_threshold) { 254 throw new OAuthException("Expired timestamp, yours $timestamp, ours $now"); 255 } 256 } 257 258 /** 259 * check that the nonce is not repeated 260 * @param $consumer 261 * @param $token 262 * @param $nonce 263 * @param $timestamp 264 * @throws OAuthException 265 */ 266 private function check_nonce($consumer, $token, $nonce, $timestamp) 267 { 268 if (!$nonce) { 269 throw new OAuthException('Missing nonce parameter. The parameter is required'); 270 } 271 272 // verify that the nonce is unique 273 $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp); 274 if ($found) { 275 throw new OAuthException("Nonce already used: $nonce"); 276 } 277 } 278} 279