Passed
Push — master ( 064380...50d823 )
by Roeland
09:51 queued 11s
created
core/Controller/ClientFlowLoginController.php 2 patches
Indentation   +364 added lines, -364 removed lines patch added patch discarded remove patch
@@ -55,369 +55,369 @@
 block discarded – undo
55 55
 use Symfony\Component\EventDispatcher\GenericEvent;
56 56
 
57 57
 class ClientFlowLoginController extends Controller {
58
-	/** @var IUserSession */
59
-	private $userSession;
60
-	/** @var IL10N */
61
-	private $l10n;
62
-	/** @var Defaults */
63
-	private $defaults;
64
-	/** @var ISession */
65
-	private $session;
66
-	/** @var IProvider */
67
-	private $tokenProvider;
68
-	/** @var ISecureRandom */
69
-	private $random;
70
-	/** @var IURLGenerator */
71
-	private $urlGenerator;
72
-	/** @var ClientMapper */
73
-	private $clientMapper;
74
-	/** @var AccessTokenMapper */
75
-	private $accessTokenMapper;
76
-	/** @var ICrypto */
77
-	private $crypto;
78
-	/** @var EventDispatcherInterface */
79
-	private $eventDispatcher;
80
-
81
-	public const stateName = 'client.flow.state.token';
82
-
83
-	/**
84
-	 * @param string $appName
85
-	 * @param IRequest $request
86
-	 * @param IUserSession $userSession
87
-	 * @param IL10N $l10n
88
-	 * @param Defaults $defaults
89
-	 * @param ISession $session
90
-	 * @param IProvider $tokenProvider
91
-	 * @param ISecureRandom $random
92
-	 * @param IURLGenerator $urlGenerator
93
-	 * @param ClientMapper $clientMapper
94
-	 * @param AccessTokenMapper $accessTokenMapper
95
-	 * @param ICrypto $crypto
96
-	 * @param EventDispatcherInterface $eventDispatcher
97
-	 */
98
-	public function __construct($appName,
99
-								IRequest $request,
100
-								IUserSession $userSession,
101
-								IL10N $l10n,
102
-								Defaults $defaults,
103
-								ISession $session,
104
-								IProvider $tokenProvider,
105
-								ISecureRandom $random,
106
-								IURLGenerator $urlGenerator,
107
-								ClientMapper $clientMapper,
108
-								AccessTokenMapper $accessTokenMapper,
109
-								ICrypto $crypto,
110
-								EventDispatcherInterface $eventDispatcher) {
111
-		parent::__construct($appName, $request);
112
-		$this->userSession = $userSession;
113
-		$this->l10n = $l10n;
114
-		$this->defaults = $defaults;
115
-		$this->session = $session;
116
-		$this->tokenProvider = $tokenProvider;
117
-		$this->random = $random;
118
-		$this->urlGenerator = $urlGenerator;
119
-		$this->clientMapper = $clientMapper;
120
-		$this->accessTokenMapper = $accessTokenMapper;
121
-		$this->crypto = $crypto;
122
-		$this->eventDispatcher = $eventDispatcher;
123
-	}
124
-
125
-	/**
126
-	 * @return string
127
-	 */
128
-	private function getClientName() {
129
-		$userAgent = $this->request->getHeader('USER_AGENT');
130
-		return $userAgent !== '' ? $userAgent : 'unknown';
131
-	}
132
-
133
-	/**
134
-	 * @param string $stateToken
135
-	 * @return bool
136
-	 */
137
-	private function isValidToken($stateToken) {
138
-		$currentToken = $this->session->get(self::stateName);
139
-		if (!is_string($stateToken) || !is_string($currentToken)) {
140
-			return false;
141
-		}
142
-		return hash_equals($currentToken, $stateToken);
143
-	}
144
-
145
-	/**
146
-	 * @return StandaloneTemplateResponse
147
-	 */
148
-	private function stateTokenForbiddenResponse() {
149
-		$response = new StandaloneTemplateResponse(
150
-			$this->appName,
151
-			'403',
152
-			[
153
-				'message' => $this->l10n->t('State token does not match'),
154
-			],
155
-			'guest'
156
-		);
157
-		$response->setStatus(Http::STATUS_FORBIDDEN);
158
-		return $response;
159
-	}
160
-
161
-	/**
162
-	 * @PublicPage
163
-	 * @NoCSRFRequired
164
-	 * @UseSession
165
-	 *
166
-	 * @param string $clientIdentifier
167
-	 *
168
-	 * @return StandaloneTemplateResponse
169
-	 */
170
-	public function showAuthPickerPage($clientIdentifier = '') {
171
-		$clientName = $this->getClientName();
172
-		$client = null;
173
-		if ($clientIdentifier !== '') {
174
-			$client = $this->clientMapper->getByIdentifier($clientIdentifier);
175
-			$clientName = $client->getName();
176
-		}
177
-
178
-		// No valid clientIdentifier given and no valid API Request (APIRequest header not set)
179
-		$clientRequest = $this->request->getHeader('OCS-APIREQUEST');
180
-		if ($clientRequest !== 'true' && $client === null) {
181
-			return new StandaloneTemplateResponse(
182
-				$this->appName,
183
-				'error',
184
-				[
185
-					'errors' =>
186
-					[
187
-						[
188
-							'error' => 'Access Forbidden',
189
-							'hint' => 'Invalid request',
190
-						],
191
-					],
192
-				],
193
-				'guest'
194
-			);
195
-		}
196
-
197
-		$stateToken = $this->random->generate(
198
-			64,
199
-			ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
200
-		);
201
-		$this->session->set(self::stateName, $stateToken);
202
-
203
-		$csp = new Http\ContentSecurityPolicy();
204
-		if ($client) {
205
-			$csp->addAllowedFormActionDomain($client->getRedirectUri());
206
-		} else {
207
-			$csp->addAllowedFormActionDomain('nc://*');
208
-		}
209
-
210
-		$response = new StandaloneTemplateResponse(
211
-			$this->appName,
212
-			'loginflow/authpicker',
213
-			[
214
-				'client' => $clientName,
215
-				'clientIdentifier' => $clientIdentifier,
216
-				'instanceName' => $this->defaults->getName(),
217
-				'urlGenerator' => $this->urlGenerator,
218
-				'stateToken' => $stateToken,
219
-				'serverHost' => $this->getServerPath(),
220
-				'oauthState' => $this->session->get('oauth.state'),
221
-			],
222
-			'guest'
223
-		);
224
-
225
-		$response->setContentSecurityPolicy($csp);
226
-		return $response;
227
-	}
228
-
229
-	/**
230
-	 * @NoAdminRequired
231
-	 * @NoCSRFRequired
232
-	 * @NoSameSiteCookieRequired
233
-	 * @UseSession
234
-	 *
235
-	 * @param string $stateToken
236
-	 * @param string $clientIdentifier
237
-	 * @return StandaloneTemplateResponse
238
-	 */
239
-	public function grantPage($stateToken = '',
240
-								 $clientIdentifier = '') {
241
-		if (!$this->isValidToken($stateToken)) {
242
-			return $this->stateTokenForbiddenResponse();
243
-		}
244
-
245
-		$clientName = $this->getClientName();
246
-		$client = null;
247
-		if ($clientIdentifier !== '') {
248
-			$client = $this->clientMapper->getByIdentifier($clientIdentifier);
249
-			$clientName = $client->getName();
250
-		}
251
-
252
-		$csp = new Http\ContentSecurityPolicy();
253
-		if ($client) {
254
-			$csp->addAllowedFormActionDomain($client->getRedirectUri());
255
-		} else {
256
-			$csp->addAllowedFormActionDomain('nc://*');
257
-		}
258
-
259
-		$response = new StandaloneTemplateResponse(
260
-			$this->appName,
261
-			'loginflow/grant',
262
-			[
263
-				'client' => $clientName,
264
-				'clientIdentifier' => $clientIdentifier,
265
-				'instanceName' => $this->defaults->getName(),
266
-				'urlGenerator' => $this->urlGenerator,
267
-				'stateToken' => $stateToken,
268
-				'serverHost' => $this->getServerPath(),
269
-				'oauthState' => $this->session->get('oauth.state'),
270
-			],
271
-			'guest'
272
-		);
273
-
274
-		$response->setContentSecurityPolicy($csp);
275
-		return $response;
276
-	}
277
-
278
-	/**
279
-	 * @NoAdminRequired
280
-	 * @UseSession
281
-	 *
282
-	 * @param string $stateToken
283
-	 * @param string $clientIdentifier
284
-	 * @return Http\RedirectResponse|Response
285
-	 */
286
-	public function generateAppPassword($stateToken,
287
-										$clientIdentifier = '') {
288
-		if (!$this->isValidToken($stateToken)) {
289
-			$this->session->remove(self::stateName);
290
-			return $this->stateTokenForbiddenResponse();
291
-		}
292
-
293
-		$this->session->remove(self::stateName);
294
-
295
-		try {
296
-			$sessionId = $this->session->getId();
297
-		} catch (SessionNotAvailableException $ex) {
298
-			$response = new Response();
299
-			$response->setStatus(Http::STATUS_FORBIDDEN);
300
-			return $response;
301
-		}
302
-
303
-		try {
304
-			$sessionToken = $this->tokenProvider->getToken($sessionId);
305
-			$loginName = $sessionToken->getLoginName();
306
-			try {
307
-				$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
308
-			} catch (PasswordlessTokenException $ex) {
309
-				$password = null;
310
-			}
311
-		} catch (InvalidTokenException $ex) {
312
-			$response = new Response();
313
-			$response->setStatus(Http::STATUS_FORBIDDEN);
314
-			return $response;
315
-		}
316
-
317
-		$clientName = $this->getClientName();
318
-		$client = false;
319
-		if ($clientIdentifier !== '') {
320
-			$client = $this->clientMapper->getByIdentifier($clientIdentifier);
321
-			$clientName = $client->getName();
322
-		}
323
-
324
-		$token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
325
-		$uid = $this->userSession->getUser()->getUID();
326
-		$generatedToken = $this->tokenProvider->generateToken(
327
-			$token,
328
-			$uid,
329
-			$loginName,
330
-			$password,
331
-			$clientName,
332
-			IToken::PERMANENT_TOKEN,
333
-			IToken::DO_NOT_REMEMBER
334
-		);
335
-
336
-		if ($client) {
337
-			$code = $this->random->generate(128, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
338
-			$accessToken = new AccessToken();
339
-			$accessToken->setClientId($client->getId());
340
-			$accessToken->setEncryptedToken($this->crypto->encrypt($token, $code));
341
-			$accessToken->setHashedCode(hash('sha512', $code));
342
-			$accessToken->setTokenId($generatedToken->getId());
343
-			$this->accessTokenMapper->insert($accessToken);
344
-
345
-			$redirectUri = $client->getRedirectUri();
58
+    /** @var IUserSession */
59
+    private $userSession;
60
+    /** @var IL10N */
61
+    private $l10n;
62
+    /** @var Defaults */
63
+    private $defaults;
64
+    /** @var ISession */
65
+    private $session;
66
+    /** @var IProvider */
67
+    private $tokenProvider;
68
+    /** @var ISecureRandom */
69
+    private $random;
70
+    /** @var IURLGenerator */
71
+    private $urlGenerator;
72
+    /** @var ClientMapper */
73
+    private $clientMapper;
74
+    /** @var AccessTokenMapper */
75
+    private $accessTokenMapper;
76
+    /** @var ICrypto */
77
+    private $crypto;
78
+    /** @var EventDispatcherInterface */
79
+    private $eventDispatcher;
80
+
81
+    public const stateName = 'client.flow.state.token';
82
+
83
+    /**
84
+     * @param string $appName
85
+     * @param IRequest $request
86
+     * @param IUserSession $userSession
87
+     * @param IL10N $l10n
88
+     * @param Defaults $defaults
89
+     * @param ISession $session
90
+     * @param IProvider $tokenProvider
91
+     * @param ISecureRandom $random
92
+     * @param IURLGenerator $urlGenerator
93
+     * @param ClientMapper $clientMapper
94
+     * @param AccessTokenMapper $accessTokenMapper
95
+     * @param ICrypto $crypto
96
+     * @param EventDispatcherInterface $eventDispatcher
97
+     */
98
+    public function __construct($appName,
99
+                                IRequest $request,
100
+                                IUserSession $userSession,
101
+                                IL10N $l10n,
102
+                                Defaults $defaults,
103
+                                ISession $session,
104
+                                IProvider $tokenProvider,
105
+                                ISecureRandom $random,
106
+                                IURLGenerator $urlGenerator,
107
+                                ClientMapper $clientMapper,
108
+                                AccessTokenMapper $accessTokenMapper,
109
+                                ICrypto $crypto,
110
+                                EventDispatcherInterface $eventDispatcher) {
111
+        parent::__construct($appName, $request);
112
+        $this->userSession = $userSession;
113
+        $this->l10n = $l10n;
114
+        $this->defaults = $defaults;
115
+        $this->session = $session;
116
+        $this->tokenProvider = $tokenProvider;
117
+        $this->random = $random;
118
+        $this->urlGenerator = $urlGenerator;
119
+        $this->clientMapper = $clientMapper;
120
+        $this->accessTokenMapper = $accessTokenMapper;
121
+        $this->crypto = $crypto;
122
+        $this->eventDispatcher = $eventDispatcher;
123
+    }
124
+
125
+    /**
126
+     * @return string
127
+     */
128
+    private function getClientName() {
129
+        $userAgent = $this->request->getHeader('USER_AGENT');
130
+        return $userAgent !== '' ? $userAgent : 'unknown';
131
+    }
132
+
133
+    /**
134
+     * @param string $stateToken
135
+     * @return bool
136
+     */
137
+    private function isValidToken($stateToken) {
138
+        $currentToken = $this->session->get(self::stateName);
139
+        if (!is_string($stateToken) || !is_string($currentToken)) {
140
+            return false;
141
+        }
142
+        return hash_equals($currentToken, $stateToken);
143
+    }
144
+
145
+    /**
146
+     * @return StandaloneTemplateResponse
147
+     */
148
+    private function stateTokenForbiddenResponse() {
149
+        $response = new StandaloneTemplateResponse(
150
+            $this->appName,
151
+            '403',
152
+            [
153
+                'message' => $this->l10n->t('State token does not match'),
154
+            ],
155
+            'guest'
156
+        );
157
+        $response->setStatus(Http::STATUS_FORBIDDEN);
158
+        return $response;
159
+    }
160
+
161
+    /**
162
+     * @PublicPage
163
+     * @NoCSRFRequired
164
+     * @UseSession
165
+     *
166
+     * @param string $clientIdentifier
167
+     *
168
+     * @return StandaloneTemplateResponse
169
+     */
170
+    public function showAuthPickerPage($clientIdentifier = '') {
171
+        $clientName = $this->getClientName();
172
+        $client = null;
173
+        if ($clientIdentifier !== '') {
174
+            $client = $this->clientMapper->getByIdentifier($clientIdentifier);
175
+            $clientName = $client->getName();
176
+        }
177
+
178
+        // No valid clientIdentifier given and no valid API Request (APIRequest header not set)
179
+        $clientRequest = $this->request->getHeader('OCS-APIREQUEST');
180
+        if ($clientRequest !== 'true' && $client === null) {
181
+            return new StandaloneTemplateResponse(
182
+                $this->appName,
183
+                'error',
184
+                [
185
+                    'errors' =>
186
+                    [
187
+                        [
188
+                            'error' => 'Access Forbidden',
189
+                            'hint' => 'Invalid request',
190
+                        ],
191
+                    ],
192
+                ],
193
+                'guest'
194
+            );
195
+        }
196
+
197
+        $stateToken = $this->random->generate(
198
+            64,
199
+            ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS
200
+        );
201
+        $this->session->set(self::stateName, $stateToken);
202
+
203
+        $csp = new Http\ContentSecurityPolicy();
204
+        if ($client) {
205
+            $csp->addAllowedFormActionDomain($client->getRedirectUri());
206
+        } else {
207
+            $csp->addAllowedFormActionDomain('nc://*');
208
+        }
209
+
210
+        $response = new StandaloneTemplateResponse(
211
+            $this->appName,
212
+            'loginflow/authpicker',
213
+            [
214
+                'client' => $clientName,
215
+                'clientIdentifier' => $clientIdentifier,
216
+                'instanceName' => $this->defaults->getName(),
217
+                'urlGenerator' => $this->urlGenerator,
218
+                'stateToken' => $stateToken,
219
+                'serverHost' => $this->getServerPath(),
220
+                'oauthState' => $this->session->get('oauth.state'),
221
+            ],
222
+            'guest'
223
+        );
224
+
225
+        $response->setContentSecurityPolicy($csp);
226
+        return $response;
227
+    }
228
+
229
+    /**
230
+     * @NoAdminRequired
231
+     * @NoCSRFRequired
232
+     * @NoSameSiteCookieRequired
233
+     * @UseSession
234
+     *
235
+     * @param string $stateToken
236
+     * @param string $clientIdentifier
237
+     * @return StandaloneTemplateResponse
238
+     */
239
+    public function grantPage($stateToken = '',
240
+                                    $clientIdentifier = '') {
241
+        if (!$this->isValidToken($stateToken)) {
242
+            return $this->stateTokenForbiddenResponse();
243
+        }
244
+
245
+        $clientName = $this->getClientName();
246
+        $client = null;
247
+        if ($clientIdentifier !== '') {
248
+            $client = $this->clientMapper->getByIdentifier($clientIdentifier);
249
+            $clientName = $client->getName();
250
+        }
251
+
252
+        $csp = new Http\ContentSecurityPolicy();
253
+        if ($client) {
254
+            $csp->addAllowedFormActionDomain($client->getRedirectUri());
255
+        } else {
256
+            $csp->addAllowedFormActionDomain('nc://*');
257
+        }
258
+
259
+        $response = new StandaloneTemplateResponse(
260
+            $this->appName,
261
+            'loginflow/grant',
262
+            [
263
+                'client' => $clientName,
264
+                'clientIdentifier' => $clientIdentifier,
265
+                'instanceName' => $this->defaults->getName(),
266
+                'urlGenerator' => $this->urlGenerator,
267
+                'stateToken' => $stateToken,
268
+                'serverHost' => $this->getServerPath(),
269
+                'oauthState' => $this->session->get('oauth.state'),
270
+            ],
271
+            'guest'
272
+        );
273
+
274
+        $response->setContentSecurityPolicy($csp);
275
+        return $response;
276
+    }
277
+
278
+    /**
279
+     * @NoAdminRequired
280
+     * @UseSession
281
+     *
282
+     * @param string $stateToken
283
+     * @param string $clientIdentifier
284
+     * @return Http\RedirectResponse|Response
285
+     */
286
+    public function generateAppPassword($stateToken,
287
+                                        $clientIdentifier = '') {
288
+        if (!$this->isValidToken($stateToken)) {
289
+            $this->session->remove(self::stateName);
290
+            return $this->stateTokenForbiddenResponse();
291
+        }
292
+
293
+        $this->session->remove(self::stateName);
294
+
295
+        try {
296
+            $sessionId = $this->session->getId();
297
+        } catch (SessionNotAvailableException $ex) {
298
+            $response = new Response();
299
+            $response->setStatus(Http::STATUS_FORBIDDEN);
300
+            return $response;
301
+        }
302
+
303
+        try {
304
+            $sessionToken = $this->tokenProvider->getToken($sessionId);
305
+            $loginName = $sessionToken->getLoginName();
306
+            try {
307
+                $password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
308
+            } catch (PasswordlessTokenException $ex) {
309
+                $password = null;
310
+            }
311
+        } catch (InvalidTokenException $ex) {
312
+            $response = new Response();
313
+            $response->setStatus(Http::STATUS_FORBIDDEN);
314
+            return $response;
315
+        }
316
+
317
+        $clientName = $this->getClientName();
318
+        $client = false;
319
+        if ($clientIdentifier !== '') {
320
+            $client = $this->clientMapper->getByIdentifier($clientIdentifier);
321
+            $clientName = $client->getName();
322
+        }
323
+
324
+        $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
325
+        $uid = $this->userSession->getUser()->getUID();
326
+        $generatedToken = $this->tokenProvider->generateToken(
327
+            $token,
328
+            $uid,
329
+            $loginName,
330
+            $password,
331
+            $clientName,
332
+            IToken::PERMANENT_TOKEN,
333
+            IToken::DO_NOT_REMEMBER
334
+        );
335
+
336
+        if ($client) {
337
+            $code = $this->random->generate(128, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
338
+            $accessToken = new AccessToken();
339
+            $accessToken->setClientId($client->getId());
340
+            $accessToken->setEncryptedToken($this->crypto->encrypt($token, $code));
341
+            $accessToken->setHashedCode(hash('sha512', $code));
342
+            $accessToken->setTokenId($generatedToken->getId());
343
+            $this->accessTokenMapper->insert($accessToken);
344
+
345
+            $redirectUri = $client->getRedirectUri();
346 346
 			
347
-			if (parse_url($redirectUri, PHP_URL_QUERY)) {
348
-				$redirectUri .= '&';
349
-			} else {
350
-				$redirectUri .= '?';
351
-			}
352
-
353
-			$redirectUri .= sprintf(
354
-				'state=%s&code=%s',
355
-				urlencode($this->session->get('oauth.state')),
356
-				urlencode($code)
357
-			);
358
-			$this->session->remove('oauth.state');
359
-		} else {
360
-			$redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
361
-
362
-			// Clear the token from the login here
363
-			$this->tokenProvider->invalidateToken($sessionId);
364
-		}
365
-
366
-		$event = new GenericEvent($generatedToken);
367
-		$this->eventDispatcher->dispatch('app_password_created', $event);
368
-
369
-		return new Http\RedirectResponse($redirectUri);
370
-	}
371
-
372
-	/**
373
-	 * @PublicPage
374
-	 */
375
-	public function apptokenRedirect(string $stateToken, string $user, string $password) {
376
-		if (!$this->isValidToken($stateToken)) {
377
-			return $this->stateTokenForbiddenResponse();
378
-		}
379
-
380
-		try {
381
-			$token = $this->tokenProvider->getToken($password);
382
-			if ($token->getLoginName() !== $user) {
383
-				throw new InvalidTokenException('login name does not match');
384
-			}
385
-		} catch (InvalidTokenException $e) {
386
-			$response = new StandaloneTemplateResponse(
387
-				$this->appName,
388
-				'403',
389
-				[
390
-					'message' => $this->l10n->t('Invalid app password'),
391
-				],
392
-				'guest'
393
-			);
394
-			$response->setStatus(Http::STATUS_FORBIDDEN);
395
-			return $response;
396
-		}
397
-
398
-		$redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($user) . '&password:' . urlencode($password);
399
-		return new Http\RedirectResponse($redirectUri);
400
-	}
401
-
402
-	private function getServerPath(): string {
403
-		$serverPostfix = '';
404
-
405
-		if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
406
-			$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
407
-		} elseif (strpos($this->request->getRequestUri(), '/login/flow') !== false) {
408
-			$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/flow'));
409
-		}
410
-
411
-		$protocol = $this->request->getServerProtocol();
412
-
413
-		if ($protocol !== "https") {
414
-			$xForwardedProto = $this->request->getHeader('X-Forwarded-Proto');
415
-			$xForwardedSSL = $this->request->getHeader('X-Forwarded-Ssl');
416
-			if ($xForwardedProto === 'https' || $xForwardedSSL === 'on') {
417
-				$protocol = 'https';
418
-			}
419
-		}
420
-
421
-		return $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
422
-	}
347
+            if (parse_url($redirectUri, PHP_URL_QUERY)) {
348
+                $redirectUri .= '&';
349
+            } else {
350
+                $redirectUri .= '?';
351
+            }
352
+
353
+            $redirectUri .= sprintf(
354
+                'state=%s&code=%s',
355
+                urlencode($this->session->get('oauth.state')),
356
+                urlencode($code)
357
+            );
358
+            $this->session->remove('oauth.state');
359
+        } else {
360
+            $redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
361
+
362
+            // Clear the token from the login here
363
+            $this->tokenProvider->invalidateToken($sessionId);
364
+        }
365
+
366
+        $event = new GenericEvent($generatedToken);
367
+        $this->eventDispatcher->dispatch('app_password_created', $event);
368
+
369
+        return new Http\RedirectResponse($redirectUri);
370
+    }
371
+
372
+    /**
373
+     * @PublicPage
374
+     */
375
+    public function apptokenRedirect(string $stateToken, string $user, string $password) {
376
+        if (!$this->isValidToken($stateToken)) {
377
+            return $this->stateTokenForbiddenResponse();
378
+        }
379
+
380
+        try {
381
+            $token = $this->tokenProvider->getToken($password);
382
+            if ($token->getLoginName() !== $user) {
383
+                throw new InvalidTokenException('login name does not match');
384
+            }
385
+        } catch (InvalidTokenException $e) {
386
+            $response = new StandaloneTemplateResponse(
387
+                $this->appName,
388
+                '403',
389
+                [
390
+                    'message' => $this->l10n->t('Invalid app password'),
391
+                ],
392
+                'guest'
393
+            );
394
+            $response->setStatus(Http::STATUS_FORBIDDEN);
395
+            return $response;
396
+        }
397
+
398
+        $redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($user) . '&password:' . urlencode($password);
399
+        return new Http\RedirectResponse($redirectUri);
400
+    }
401
+
402
+    private function getServerPath(): string {
403
+        $serverPostfix = '';
404
+
405
+        if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
406
+            $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
407
+        } elseif (strpos($this->request->getRequestUri(), '/login/flow') !== false) {
408
+            $serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/flow'));
409
+        }
410
+
411
+        $protocol = $this->request->getServerProtocol();
412
+
413
+        if ($protocol !== "https") {
414
+            $xForwardedProto = $this->request->getHeader('X-Forwarded-Proto');
415
+            $xForwardedSSL = $this->request->getHeader('X-Forwarded-Ssl');
416
+            if ($xForwardedProto === 'https' || $xForwardedSSL === 'on') {
417
+                $protocol = 'https';
418
+            }
419
+        }
420
+
421
+        return $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
422
+    }
423 423
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 			);
358 358
 			$this->session->remove('oauth.state');
359 359
 		} else {
360
-			$redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
360
+			$redirectUri = 'nc://login/server:'.$this->getServerPath().'&user:'.urlencode($loginName).'&password:'.urlencode($token);
361 361
 
362 362
 			// Clear the token from the login here
363 363
 			$this->tokenProvider->invalidateToken($sessionId);
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 			return $response;
396 396
 		}
397 397
 
398
-		$redirectUri = 'nc://login/server:' . $this->getServerPath() . '&user:' . urlencode($user) . '&password:' . urlencode($password);
398
+		$redirectUri = 'nc://login/server:'.$this->getServerPath().'&user:'.urlencode($user).'&password:'.urlencode($password);
399 399
 		return new Http\RedirectResponse($redirectUri);
400 400
 	}
401 401
 
@@ -418,6 +418,6 @@  discard block
 block discarded – undo
418 418
 			}
419 419
 		}
420 420
 
421
-		return $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
421
+		return $protocol."://".$this->request->getServerHost().$serverPostfix;
422 422
 	}
423 423
 }
Please login to merge, or discard this patch.