Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ cd plugin-oauth2
composer install
```

# Updating from version 3.0.x

Some settings are now mandatory, clients that do not follow them are refused (the reason is written in Galette logs):
- each client must declare its `redirect_uri`: the callback URL of the client application, exactly as the application sends it. Use a list if the application uses several URLs.
- each client must have its own `password`; the `global` password is no longer used, and the `abc123` example password is refused.
- only the "authorization code" and "refresh token" grants are available.
- scopes from the `scopes` entry are checked by default on the authorization screen; they are no longer given if the member unchecks them.
- members already logged in to the authorization screen will have to log in again.

# Updating to version 3.0.0

Before updating to version 3.0.0, please take care of the following:
Expand Down Expand Up @@ -43,19 +52,24 @@ Rename `config/config.yml.dist` to `config/config.yml` and edit according to you

```
global:
password: abc123
title: 'Galette'

galette_flarum:
password: 'a-long-random-secret'
title: 'Forum Flarum'
redirect_uri: 'http://192.168.1.99/flarum/public/auth/passport'
redirect_logout: 'http://192.168.1.99/flarum/public'
galette_nc:
password: 'another-long-random-secret'
title: 'Nextcloud'
redirect_uri: 'http://192.168.1.99/nextcloud/apps/sociallogin/custom_oauth2/galette'
redirect_logout: 'http://192.168.1.99/nextcloud'
scopes:
- member:groups
galette_xxxxx:
```

`password` and `redirect_uri` are mandatory for each client. `redirect_uri` can be a list of URLs.

The corresponding Flarum configuration:

![Flarum configuration example](examples/flarum.png)
Expand Down
25 changes: 1 addition & 24 deletions _dependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use GaletteOAuth2\Repositories\ClientRepository;
use GaletteOAuth2\Repositories\RefreshTokenRepository;
use GaletteOAuth2\Repositories\ScopeRepository;
use GaletteOAuth2\Repositories\UserRepository;
use GaletteOAuth2\Tools\Config;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Grant\AuthCodeGrant;
Expand Down Expand Up @@ -114,8 +113,7 @@ function (ContainerInterface $container) {
new DateInterval('PT10M'),
);

// Enable the password grant on the server
// with a token TTL of 1 hour
// Enable the authorization code grant on the server
$server->enableGrantType(
$grant,
// access tokens will expire after 1 hour
Expand All @@ -133,27 +131,6 @@ function (ContainerInterface $container) {
new DateInterval('PT1H'),
);

//--
$userRepository = new UserRepository($container); // instance of UserRepositoryInterface
$grant = new \League\OAuth2\Server\Grant\PasswordGrant(
$userRepository,
$refreshTokenRepository,
);

$grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month

// Enable the password grant on the server
$server->enableGrantType(
$grant,
new \DateInterval('PT1H'), // access tokens will expire after 1 hour
);

// Enable the client credentials grant on the server
$server->enableGrantType(
new \League\OAuth2\Server\Grant\ClientCredentialsGrant(),
new \DateInterval('PT1H'), // access tokens will expire after 1 hour
);

return $server;
},
);
Expand Down
5 changes: 4 additions & 1 deletion config/config.yml.dist
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
global:
title: 'Galette'
password: abc123
encryption_key: 'your-encryption-key-here' # Replace with a secure random string
galette_flarum:
password: '' # required: a long random secret, shared with the client application
title: 'Forum Flarum'
redirect_logout: 'http://192.168.1.99/flarum/public'
redirect_uri: 'http://192.168.1.99/flarum/public/auth/passport'
authorize: teamonly
galette_nc:
password: '' # required: one secret per client
title: 'Le cloud de votre association'
redirect_logout: 'http://192.168.1.99/nextcloud'
redirect_uri: 'http://192.168.1.99/nextcloud/apps/sociallogin/custom_oauth2/galette'
authorize: teamonly
scopes:
- member
Expand Down
5 changes: 2 additions & 3 deletions lib/GaletteOAuth2/Controllers/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ public function user(Request $request, Response $response): Response
$this->container,
$oauth_user_id,
UserHelper::getAuthorization($this->config, $client_id),
//only scopes the user has consented to, stored in the token
UserHelper::mergeScopes(
$this->config,
null,
$client_id,
$rep->getAttribute('oauth_scopes')
),
Expand All @@ -88,8 +89,6 @@ public function user(Request $request, Response $response): Response
return $response->withStatus(401);
}

Debug::log('api/user() return data = ' . Debug::printVar($data));

$response->getBody()->write(json_encode($data));
Debug::log('api/user() exit.');

Expand Down
68 changes: 21 additions & 47 deletions lib/GaletteOAuth2/Controllers/AuthorizationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,36 +75,6 @@ public function authorize(Request $request, Response $response): Response|Respon
$queryParams = $request->getQueryParams();
$client_id = $queryParams['client_id'];

//Save redirect_uri (it's not possible with Sessions)
//FIXME [JC]: I really do not like the idea of using a file on disk;
// this may also cause severe issues in case of concurrent logins
if (isset($queryParams['redirect_uri'])) {
$key = $client_id . '.redirect_uri';
if (!isset($this->session->$client_id)) {
$this->session->$client_id = new \stdClass();
}
$this->session->$client_id->redirect_uri = $queryParams['redirect_uri'];
$v = $queryParams['redirect_uri'];

if ($this->config->get($key, '') === '') {
$filename = OAUTH2_PREFIX . '_' . $key . '.txt';
Debug::log("Auto add redirect_uri to cache $filename: $v");

$this->config->set($key, $v);
$stream = fopen(GALETTE_CACHE_DIR . '/' . $filename, 'w+');
fwrite(
$stream,
$v
);
fclose($stream);

Analog::log(
'Auto add redirect_uri ok.',
Analog::DEBUG
);
}
}

// Validate the HTTP request and return an AuthorizationRequest object.
// The auth request object can be serialized into a user's session
$authRequest = $server->validateAuthorizationRequest($request);
Expand Down Expand Up @@ -147,10 +117,7 @@ public function authorize(Request $request, Response $response): Response|Respon
} catch (OAuthServerException $exception) {
return $exception->generateHttpResponse($response);
} catch (Exception $exception) {
$body = $response->getBody();
$body->write($exception->getMessage());

return $response->withStatus(500)->withBody($body);
return $this->errorResponse($response, $exception);
}
}

Expand Down Expand Up @@ -191,7 +158,10 @@ public function doAuthorize(Request $request, Response $response): Response|Resp
$req_scopes = [];
$srepo = new ScopeRepository();
foreach ($scopes as $scope) {
$req_scopes[] = $srepo->getScopeEntityByIdentifier($scope);
$scope_entity = $srepo->getScopeEntityByIdentifier($scope);
if ($scope_entity !== null) {
$req_scopes[] = $scope_entity;
}
}
$authRequest->setScopes($req_scopes);
} else {
Expand All @@ -217,10 +187,7 @@ public function doAuthorize(Request $request, Response $response): Response|Resp
} catch (OAuthServerException $exception) {
return $exception->generateHttpResponse($response);
} catch (Exception $exception) {
$body = $response->getBody();
$body->write($exception->getMessage());

return $response->withStatus(500)->withBody($body);
return $this->errorResponse($response, $exception);
} finally {
$this->login->logout();
}
Expand All @@ -243,15 +210,22 @@ public function token(Request $request, Response $response): Response|ResponseIn
// All instances of OAuthServerException can be converted to a PSR-7 response
return $exception->generateHttpResponse($response);
} catch (Exception $exception) {
Debug::log(
'authorization/Exception: '
. $exception->getMessage() . '<br>' . $exception->getTraceAsString()
);
// Catch unexpected exceptions
$body = $response->getBody();
$body->write($exception->getMessage());

return $response->withStatus(500)->withBody($body);
return $this->errorResponse($response, $exception);
}
}

/**
* Log an unexpected error, without disclosing its details
*/
private function errorResponse(Response $response, Exception $exception): ResponseInterface
{
Analog::log(
'OAuth2 error: ' . $exception->getMessage() . "\n" . $exception->getTraceAsString(),
Analog::ERROR
);
$response->getBody()->write(_T('An error occurred', 'oauth2'));

return $response->withStatus(500);
}
}
3 changes: 3 additions & 0 deletions lib/GaletteOAuth2/Controllers/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public function doLogin(Request $request, Response $response): Response
//Try login
//FIXME: for both isLoggedIn and user_id, we can rely on login object stored in session
$this->session->isLoggedIn = 'no';
unset($this->session->client_id);
$this->session->user_id = $uid = UserHelper::login($this->container, $params['login'], $params['password']);
Debug::log("UserHelper::login({$params['login']}) return '{$uid}'");

Expand Down Expand Up @@ -155,6 +156,7 @@ public function doLogin(Request $request, Response $response): Response

//FIXME: for both isLoggedIn and user_id, we can rely on login object stored in session
$this->session->isLoggedIn = 'yes';
$this->session->client_id = $client_id;

// User is logged in, redirect them to authorize
$url_params = [
Expand Down Expand Up @@ -183,6 +185,7 @@ public function logout(Request $request, Response $response): Response
unset(
$this->session->user_id,
$this->session->isLoggedIn,
$this->session->client_id,
$this->session->request_args
);
session_destroy();
Expand Down
6 changes: 4 additions & 2 deletions lib/GaletteOAuth2/Middleware/Authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ public function __invoke(Request $request, RequestHandler $handler): Response
}

$loggedIn = $this->session->isLoggedIn ?? '';
//login rights have been checked for one client only
$loggedClient = $this->session->client_id ?? null;

if ('yes' !== $loggedIn) {
if ('yes' !== $loggedIn || $loggedClient !== $client_id) {
$url = $this->routeparser->urlFor(
OAUTH2_PREFIX . '_login',
[],
['redirect_url' => $_SERVER['REQUEST_URI']],
['redirect_url' => $request->getUri()->getPath() . '?' . $request->getUri()->getQuery()],
);
Debug::log("Redirect to {$url}");

Expand Down
Loading
Loading