d02b7b8b46a5a4fc214e2f3e5fe5afa11235f870
[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 = new \OAuthProvider();
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         $res = new TemplateResponse('grauphel', 'oauthAuthorize');
122         $res->setParams(
123             array(
124                 'oauth_token' => $token->tokenKey,
125                 'formaction'  => $this->deps->urlGen->linkToRoute(
126                     'grauphel.oauth.confirm'
127                 ),
128             )
129         );
130         return $res;
131     }
132
133     /**
134      * User confirms or declines the authorization request
135      * OAuth step 2.5 of 3
136      *
137      * @NoAdminRequired
138      */
139     public function confirm()
140     {
141         $token = $this->verifyRequestToken();
142         $oauth = new OAuth();
143         $oauth->setDeps($this->deps);
144
145         try {
146             $token = $this->deps->tokens->loadAndDelete('temp', $token->tokenKey);
147         } catch (OAuthException $e) {
148             return new ErrorResponse($e->getMessage());
149         }
150
151         $authState = isset($_POST['auth']) && $_POST['auth'] == 'ok';
152         if ($authState === false) {
153             //user declined
154
155             //http://wiki.oauth.net/w/page/12238543/ProblemReporting
156             $res = new RedirectResponse(
157                 UrlHelper::addParams(
158                     $token->callback,
159                     array(
160                         'oauth_token'   => $token->tokenKey,
161                         'oauth_problem' => 'permission_denied',
162                     )
163                 )
164             );
165             $res->setStatus(Http::STATUS_SEE_OTHER);
166             return $res;
167         }
168
169         //the user is logged in and authorized
170         $provider = new \OAuthProvider();
171
172         $newToken = new Token('verify');
173         $newToken->tokenKey = $token->tokenKey;
174         $newToken->secret   = $token->secret;
175         $newToken->verifier = 'v' . bin2hex($provider->generateToken(8));
176         $newToken->user     = $this->user->getUID();
177
178         $this->deps->tokens->store($newToken);
179
180         //redirect
181         //FIXME: if no callback is given, show the token to the user
182         $res = new RedirectResponse(
183             UrlHelper::addParams(
184                 $token->callback,
185                 array(
186                     'oauth_token'    => $newToken->tokenKey,
187                     'oauth_verifier' => $newToken->verifier
188                 )
189             )
190         );
191         $res->setStatus(Http::STATUS_SEE_OTHER);
192         return $res;
193     }
194
195     protected function verifyRequestToken()
196     {
197         if (!isset($_REQUEST['oauth_token'])) {
198             return new ErrorResponse('oauth_token missing');
199         }
200
201         $oauth = new OAuth();
202         $oauth->setDeps($this->deps);
203         if (!$oauth->validateToken($_REQUEST['oauth_token'])) {
204             return new ErrorResponse('Invalid token string');
205         }
206
207         $reqToken = $_REQUEST['oauth_token'];
208
209         try {
210             $token = $this->deps->tokens->load('temp', $reqToken);
211         } catch (OAuthException $e) {
212             return new ErrorResponse($e->getMessage());
213         }
214
215         return $token;
216     }
217
218     /**
219      * Create and return a request token.
220      * OAuth step 1 of 3
221      *
222      * @NoAdminRequired
223      * @NoCSRFRequired
224      * @PublicPage
225      */
226     public function requestToken()
227     {
228         $oauth = new OAuth();
229         $oauth->setDeps($this->deps);
230         $urlGen = $this->deps->urlGen;
231
232         try {
233             $provider = new \OAuthProvider();
234             $oauth->registerHandler($provider);
235             $provider->isRequestTokenEndpoint(true);
236             $provider->checkOAuthRequest(
237                 $urlGen->getAbsoluteURL(
238                     $urlGen->linkToRoute('grauphel.oauth.requestToken')
239                 )
240             );
241
242             //store token + callback URI for later
243             $token = new Token('temp');
244             $token->tokenKey = 'r' . bin2hex($provider->generateToken(8));
245             $token->secret   = 's' . bin2hex($provider->generateToken(8));
246             $token->callback = $provider->callback;
247
248             $this->deps->tokens->store($token);
249
250             return new FormResponse(
251                 array(
252                     'oauth_token'              => $token->tokenKey,
253                     'oauth_token_secret'       => $token->secret,
254                     'oauth_callback_confirmed' => 'TRUE'
255                 )
256             );
257         } catch (OAuthException $e) {
258             return new ErrorResponse($e->getMessage());
259         } catch (\OAuthException $e) {
260             $oauth->error($e);
261         }
262     }
263 }
264 ?>