6ab17d224f64dfeae05b5ff11ce2e23a28910b0c
[grauphel.git] / controller / oauthcontroller.php
1 <?php
2 /**
3  * Part of grauphel
4  *
5  * PHP version 5
6  *
7  * @category  Tools
8  * @package   Grauphel
9  * @author    Christian Weiske <cweiske@cweiske.de>
10  * @copyright 2014 Christian Weiske
11  * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
12  * @link      http://cweiske.de/grauphel.htm
13  */
14 namespace OCA\Grauphel\Controller;
15
16 use \OCP\AppFramework\Controller;
17 use \OCP\AppFramework\Http;
18 use \OCP\AppFramework\Http\RedirectResponse;
19 use \OCP\AppFramework\Http\TemplateResponse;
20
21 use \OCA\Grauphel\Lib\Token;
22 use \OCA\Grauphel\Lib\OAuth;
23 use \OCA\Grauphel\Lib\Dependencies;
24 use \OCA\Grauphel\Lib\Response\ErrorResponse;
25 use \OCA\Grauphel\Lib\Response\FormResponse;
26 use \OCA\Grauphel\Lib\OAuthException;
27 use \OCA\Grauphel\Lib\UrlHelper;
28
29 /**
30  * OAuth handling
31  *
32  * @category  Tools
33  * @package   Grauphel
34  * @author    Christian Weiske <cweiske@cweiske.de>
35  * @copyright 2014 Christian Weiske
36  * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
37  * @version   Release: @package_version@
38  * @link      http://cweiske.de/grauphel.htm
39  */
40 class OauthController extends Controller
41 {
42     protected $user;
43
44     /**
45      * constructor of the controller
46      *
47      * @param string   $appName Name of the app
48      * @param IRequest $request Instance of the request
49      */
50     public function __construct($appName, \OCP\IRequest $request, $user)
51     {
52         parent::__construct($appName, $request);
53         $this->user = $user;
54         $this->deps = Dependencies::get();
55
56         //default http header: we assume something is broken
57         header('HTTP/1.0 500 Internal Server Error');
58     }
59
60     /**
61      * Handle out an access token after verifying the verification token
62      * OAuth step 3 of 3
63      *
64      * @NoAdminRequired
65      * @NoCSRFRequired
66      * @PublicPage
67      */
68     public function accessToken()
69     {
70         $oauth = new OAuth();
71         $oauth->setDeps($this->deps);
72         $urlGen = $this->deps->urlGen;
73
74         try {
75             $provider = OAuth::getProvider();
76             $oauth->registerHandler($provider)
77                 ->registerVerificationTokenHandler($provider);
78             $provider->checkOAuthRequest(
79                 $urlGen->getAbsoluteURL(
80                     $urlGen->linkToRoute('grauphel.oauth.accessToken')
81                 )
82             );
83
84             $token = $this->deps->tokens->loadAndDelete('verify', $provider->token);
85
86             $newToken = new Token('access');
87             $newToken->tokenKey = 'a' . bin2hex($provider->generateToken(8));
88             $newToken->secret   = 's' . bin2hex($provider->generateToken(8));
89             $newToken->user     = $token->user;
90             $this->deps->tokens->store($newToken);
91
92             return new FormResponse(
93                 array(
94                     'oauth_token'        => $newToken->tokenKey,
95                     'oauth_token_secret' => $newToken->secret,
96                 )
97             );
98         } catch (OAuthException $e) {
99             return new ErrorResponse($e->getMessage());
100         } catch (\OAuthException $e) {
101             $oauth->error($e);
102         }
103     }
104
105     /**
106      * Log the user in and let him authorize that the app may access notes
107      * OAuth step 2 of 3
108      *
109      * Page is not public and thus requires owncloud login
110      *
111      * @NoAdminRequired
112      * @NoCSRFRequired
113      */
114     public function authorize()
115     {
116         $token = $this->verifyRequestToken();
117         if (!$token instanceof Token) {
118             return $token;
119         }
120
121         $client = 'unknown';
122         if (isset($_GET['client'])) {
123             $client = $_GET['client'];
124         }
125
126         $res = new TemplateResponse('grauphel', 'oauthAuthorize');
127         $res->setParams(
128             array(
129                 'oauth_token' => $token->tokenKey,
130                 'client'      => $client,
131                 'formaction'  => $this->deps->urlGen->linkToRoute(
132                     'grauphel.oauth.confirm'
133                 ),
134             )
135         );
136         return $res;
137     }
138
139     /**
140      * User confirms or declines the authorization request
141      * OAuth step 2.5 of 3
142      *
143      * @NoAdminRequired
144      */
145     public function confirm()
146     {
147         $token = $this->verifyRequestToken();
148         $oauth = new OAuth();
149         $oauth->setDeps($this->deps);
150
151         try {
152             $token = $this->deps->tokens->loadAndDelete('temp', $token->tokenKey);
153         } catch (OAuthException $e) {
154             return new ErrorResponse($e->getMessage());
155         }
156
157         $authState = isset($_POST['auth']) && $_POST['auth'] == 'ok';
158         if ($authState === false) {
159             //user declined
160
161             //http://wiki.oauth.net/w/page/12238543/ProblemReporting
162             $res = new RedirectResponse(
163                 UrlHelper::addParams(
164                     $token->callback,
165                     array(
166                         'oauth_token'   => $token->tokenKey,
167                         'oauth_problem' => 'permission_denied',
168                     )
169                 )
170             );
171             $res->setStatus(Http::STATUS_SEE_OTHER);
172             return $res;
173         }
174
175         //the user is logged in and authorized
176         $provider = OAuth::getProvider();
177
178         $newToken = new Token('verify');
179         $newToken->tokenKey = $token->tokenKey;
180         $newToken->secret   = $token->secret;
181         $newToken->verifier = 'v' . bin2hex($provider->generateToken(8));
182         $newToken->user     = $this->user->getUID();
183
184         $this->deps->tokens->store($newToken);
185
186         //redirect
187         //FIXME: if no callback is given, show the token to the user
188         $res = new RedirectResponse(
189             UrlHelper::addParams(
190                 $token->callback,
191                 array(
192                     'oauth_token'    => $newToken->tokenKey,
193                     'oauth_verifier' => $newToken->verifier
194                 )
195             )
196         );
197         $res->setStatus(Http::STATUS_SEE_OTHER);
198         return $res;
199     }
200
201     protected function verifyRequestToken()
202     {
203         if (!isset($_REQUEST['oauth_token'])) {
204             return new ErrorResponse('oauth_token missing');
205         }
206
207         $oauth = new OAuth();
208         $oauth->setDeps($this->deps);
209         if (!$oauth->validateToken($_REQUEST['oauth_token'])) {
210             return new ErrorResponse('Invalid token string');
211         }
212
213         $reqToken = $_REQUEST['oauth_token'];
214
215         try {
216             $token = $this->deps->tokens->load('temp', $reqToken);
217         } catch (OAuthException $e) {
218             return new ErrorResponse($e->getMessage());
219         }
220
221         return $token;
222     }
223
224     /**
225      * Create and return a request token.
226      * OAuth step 1 of 3
227      *
228      * @NoAdminRequired
229      * @NoCSRFRequired
230      * @PublicPage
231      */
232     public function requestToken()
233     {
234         $oauth = new OAuth();
235         $oauth->setDeps($this->deps);
236         $urlGen = $this->deps->urlGen;
237
238         try {
239             $provider = OAuth::getProvider();
240             $oauth->registerHandler($provider);
241             $provider->isRequestTokenEndpoint(true);
242             $provider->checkOAuthRequest(
243                 $urlGen->getAbsoluteURL(
244                     $urlGen->linkToRoute('grauphel.oauth.requestToken')
245                 )
246             );
247
248             //store token + callback URI for later
249             $token = new Token('temp');
250             $token->tokenKey = 'r' . bin2hex($provider->generateToken(8));
251             $token->secret   = 's' . bin2hex($provider->generateToken(8));
252             $token->callback = $provider->callback;
253
254             $this->deps->tokens->store($token);
255
256             return new FormResponse(
257                 array(
258                     'oauth_token'              => $token->tokenKey,
259                     'oauth_token_secret'       => $token->secret,
260                     'oauth_callback_confirmed' => 'true'
261                 )
262             );
263         } catch (OAuthException $e) {
264             return new ErrorResponse($e->getMessage());
265         } catch (\OAuthException $e) {
266             $oauth->error($e);
267         }
268     }
269 }
270 ?>