Skip to content

Commit

Permalink
Add separate options for OAuth and local registration/login. Fixes #159
Browse files Browse the repository at this point in the history
…. (#200)
  • Loading branch information
nickygerritsen authored Jun 16, 2020
1 parent 051adea commit 353a177
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/Controller/OAuth/BitbucketController.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class BitbucketController extends OAuthController
*/
public function register(): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->oauth->getClient('bitbucket')->redirect(['email'], []);
}
Expand All @@ -42,7 +42,7 @@ public function auth(ClientRegistry $clientRegistry): Response
*/
public function registerCheck(Request $request, BitbucketApi $api): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->createAndAuthenticateUser(
'bitbucket',
Expand Down
4 changes: 2 additions & 2 deletions src/Controller/OAuth/BuddyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class BuddyController extends OAuthController
*/
public function register(): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->oauth->getClient('buddy')->redirect([Buddy::SCOPE_USER_EMAIL], []);
}
Expand All @@ -39,7 +39,7 @@ public function auth(): Response
*/
public function registerCheck(Request $request, BuddyApi $api): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->createAndAuthenticateUser(
'buddy',
Expand Down
4 changes: 2 additions & 2 deletions src/Controller/OAuth/GitHubController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class GitHubController extends OAuthController
*/
public function register(): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->oauth->getClient('github')->redirect(['user:email'], []);
}
Expand All @@ -44,7 +44,7 @@ public function auth(): Response
*/
public function registerCheck(Request $request, GitHubApi $api): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->createAndAuthenticateUser(
'github',
Expand Down
4 changes: 2 additions & 2 deletions src/Controller/OAuth/GitLabController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class GitLabController extends OAuthController
*/
public function register(): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->oauth->getClient('gitlab')->redirect(['read_user'], []);
}
Expand All @@ -41,7 +41,7 @@ public function auth(): Response
*/
public function registerCheck(Request $request): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureOAuthRegistrationIsEnabled();

return $this->createAndAuthenticateUser(
'gitlab',
Expand Down
6 changes: 3 additions & 3 deletions src/Controller/OAuth/OAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ protected function storeRepoToken(string $type, callable $tokenProvider, string
}
}

protected function ensureRegistrationIsEnabled(): void
protected function ensureOAuthRegistrationIsEnabled(): void
{
if (!$this->config->userRegistrationEnabled()) {
throw new NotFoundHttpException('Registration is disabled');
if (!$this->config->oauthRegistrationEnabled()) {
throw new NotFoundHttpException('Registration using OAuth is disabled');
}
}
}
12 changes: 11 additions & 1 deletion src/Controller/RegistrationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public function register(Request $request): Response
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$this->ensureLocalRegistrationIsEnabled();
$this->dispatchMessage(new CreateUser(
Uuid::uuid4()->toString(),
$email = $form->get('email')->getData(),
Expand All @@ -60,6 +61,8 @@ public function register(Request $request): Response

return $this->render('registration/register.html.twig', [
'registrationForm' => $form->createView(),
'oauthRegistrationEnabled' => $this->config->oauthRegistrationEnabled(),
'localRegistrationEnabled' => $this->config->localRegistrationEnabled(),
]);
}

Expand All @@ -68,7 +71,7 @@ public function register(Request $request): Response
*/
public function confirm(string $token): Response
{
$this->ensureRegistrationIsEnabled();
$this->ensureLocalRegistrationIsEnabled();

try {
$this->dispatchMessage(new ConfirmEmail($token));
Expand All @@ -86,4 +89,11 @@ private function ensureRegistrationIsEnabled(): void
throw new NotFoundHttpException('Registration is disabled');
}
}

private function ensureLocalRegistrationIsEnabled(): void
{
if (!$this->config->localRegistrationEnabled()) {
throw new NotFoundHttpException('Local registration is disabled');
}
}
}
9 changes: 9 additions & 0 deletions src/Controller/SecurityController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Buddy\Repman\Form\Type\User\SendResetPasswordLinkType;
use Buddy\Repman\Message\User\ResetPassword;
use Buddy\Repman\Message\User\SendPasswordResetLink;
use Buddy\Repman\Service\Config;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -17,6 +18,13 @@

class SecurityController extends AbstractController
{
private Config $config;

public function __construct(Config $config)
{
$this->config = $config;
}

/**
* @Route("/login", name="app_login")
*/
Expand All @@ -29,6 +37,7 @@ public function login(AuthenticationUtils $authenticationUtils): Response
return $this->render('security/login.html.twig', [
'last_username' => $authenticationUtils->getLastUsername(),
'error' => $authenticationUtils->getLastAuthenticationError(),
'localLoginEnabled' => $this->config->localLoginEnabled(),
]);
}

Expand Down
15 changes: 14 additions & 1 deletion src/Form/Type/Admin/ConfigType.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,24 @@ public function getBlockPrefix(): string
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('user_registration', ChoiceType::class, [
->add('local_authentication', ChoiceType::class, [
'choices' => [
'allow login and registration' => 'login_and_registration',
'allow login, disable registration' => 'login_only',
'disabled' => 'disabled',
],
'attr' => [
'class' => 'form-control selectpicker',
'data-style' => 'btn-secondary',
],
])
->add('oauth_registration', ChoiceType::class, [
'choices' => [
'enabled' => 'enabled',
'disabled' => 'disabled',
],
'label' => 'OAuth registration',
'help' => 'Note: login with OAuth can be set using the OAUTH_* environment variables',
'attr' => [
'class' => 'form-control selectpicker',
'data-style' => 'btn-secondary',
Expand Down
62 changes: 62 additions & 0 deletions src/Migrations/Version20200614133313.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace Buddy\Repman\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20200614133313 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');

$this->addSql("INSERT INTO config (key, value)
VALUES ('local_authentication', (
SELECT CASE
WHEN value = 'enabled'
THEN 'login_and_registration'
ELSE 'login_only'
END
FROM config
WHERE key = 'user_registration'
))");
$this->addSql("INSERT INTO config (key, value)
VALUES ('oauth_registration', (
SELECT value
FROM config
WHERE key = 'user_registration'
))");
$this->addSql("DELETE FROM config WHERE key = 'user_registration'");
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');

$this->addSql("INSERT INTO config (key, value)
VALUES ('user_registration', (
SELECT CASE
WHEN value = 'disabled'
THEN 'disabled'
ELSE 'enabled'
END
FROM config
WHERE key = 'local_authentication'
))");
$this->addSql("DELETE FROM config WHERE key = 'local_authentication'");
$this->addSql("DELETE FROM config WHERE key = 'oauth_registration'");
}
}
8 changes: 6 additions & 2 deletions src/Security/LoginFormAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Buddy\Repman\Security;

use Buddy\Repman\Entity\User;
use Buddy\Repman\Service\Config;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -30,18 +31,21 @@ class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements P
private UrlGeneratorInterface $urlGenerator;
private CsrfTokenManagerInterface $csrfTokenManager;
private UserPasswordEncoderInterface $passwordEncoder;
private Config $config;

public function __construct(UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
public function __construct(UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder, Config $config)
{
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
$this->config = $config;
}

public function supports(Request $request)
{
return 'app_login' === $request->attributes->get('_route')
&& $request->isMethod('POST');
&& $request->isMethod('POST')
&& $this->config->localLoginEnabled();
}

public function getCredentials(Request $request)
Expand Down
17 changes: 16 additions & 1 deletion src/Service/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,24 @@ public function get(string $key): ?string
return $this->getAll()[$key] ?? null;
}

public function localLoginEnabled(): bool
{
return $this->get('local_authentication') !== 'disabled';
}

public function localRegistrationEnabled(): bool
{
return $this->get('local_authentication') === 'login_and_registration';
}

public function oauthRegistrationEnabled(): bool
{
return $this->get('oauth_registration') === 'enabled';
}

public function userRegistrationEnabled(): bool
{
return $this->get('user_registration') === 'enabled';
return $this->localRegistrationEnabled() || $this->oauthRegistrationEnabled();
}

/**
Expand Down
10 changes: 7 additions & 3 deletions templates/registration/register.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<div class="card-title text-center">Sign up for free</div>

{% if oauth_enabled() %}
{% if oauthRegistrationEnabled and oauth_enabled() %}
<div class="text-center">
{% if oauth_enabled('github') %}
<a href="{{ url('register_github_start') }}" class="btn btn-github btn-sm">
Expand Down Expand Up @@ -40,10 +40,14 @@

<hr />

<div class="text-center"><small>or sign up with e-mail</small></div>
{% if localRegistrationEnabled %}
<div class="text-center"><small>or sign up with e-mail</small></div>
{% endif %}
{% endif %}

{{ form(registrationForm) }}
{% if localRegistrationEnabled %}
{{ form(registrationForm) }}
{% endif %}

<div class="text-center mt-5">
<small>By creating an account you agree to our <a href="https://repman.io/terms-of-service/" target="_blank" rel="noopener noreferrer">Terms & Conditions</a>.</small>
Expand Down
48 changes: 26 additions & 22 deletions templates/security/login.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,37 @@

<hr />

<div class="text-center"><small>or sign in with e-mail</small></div>
{% if localLoginEnabled %}
<div class="text-center"><small>or sign in with e-mail</small></div>
{% endif %}
{% endif %}

<div class="mb-2">
<label for="inputEmail" class="form-label">Email address</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" placeholder="Enter email" required autofocus>
</div>
<div class="mb-2">
<a href="{{ path('app_send_reset_password_link') }}" class="float-right small">I forgot password</a>
<label for="inputPassword" class="form-label">
Password
</label>
<input type="password" name="password" id="inputPassword" class="form-control" required autocomplete="off">
</div>
{% if localLoginEnabled %}
<div class="mb-2">
<label for="inputEmail" class="form-label">Email address</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" placeholder="Enter email" required autofocus>
</div>
<div class="mb-2">
<a href="{{ path('app_send_reset_password_link') }}" class="float-right small">I forgot password</a>
<label for="inputPassword" class="form-label">
Password
</label>
<input type="password" name="password" id="inputPassword" class="form-control" required autocomplete="off">
</div>

<div class="mb-2">
<label class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="_remember_me"/>
<span class="custom-control-label">Remember me</span>
</label>
</div>
<div class="mb-2">
<label class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="_remember_me"/>
<span class="custom-control-label">Remember me</span>
</label>
</div>

<div class="form-footer">
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</div>
<div class="form-footer">
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</div>

<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
{% endif %}
</div>
</form>
{% include 'component/signUpLink.html.twig' %}
Expand Down
Loading

0 comments on commit 353a177

Please sign in to comment.