Sonata Admin : Forgotten Password - symfony

I am using Sonata Admin with SonataUser/FosUser bundles.
I want to integrate the "reset password" functionality from FosUser into Sonata. Is there a quick way to :
integrate the "forgot your password" link into the sonata login page ?
integrate the functionality with the "admin/" url prefix and the sonata html/twig layout ?

I have modified the admin login template to add the reset password link, you must extend the SonataUserBundle in order to use your custom template, follow the documentation.
The custom template must have the same name and the same directory as in SonataUserBundle. Here is the template I used :
Application\Sonata\UserBundle\Resources\views\Admin\Security\login.html.twig
{% extends base_template %}
{% block content %}
<div class="connection">
<form action="{{ path("sonata_user_admin_security_check") }}" method="post">
{% if error %}
<div class="alert alert-error">{{ error|trans({}, 'SonataUserBundle') }}</div>
{% endif %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<div class="control-group">
<label for="username">{{ 'security.login.username'|trans({}, 'FOSUserBundle') }}</label>
<div class="controls">
<input type="text" id="username" name="_username" value="{{ last_username }}" class="big sonata-medium"/>
</div>
</div>
<div class="control-group">
<label for="password">{{ 'security.login.password'|trans({}, 'FOSUserBundle') }}</label>
<div class="controls">
<input type="password" id="password" name="_password" class="big sonata-medium" />
</div>
</div>
<div class="control-group">
<label for="remember_me">
<input type="checkbox" id="remember_me" name="_remember_me" value="on" />
{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
</label>
</div>
<div class="control-group">
<a href="{{ path('fos_user_resetting_request') }}">
{{ 'forgotten_password'|trans({}, 'SonataUserBundle') }}
</a>
</div>
<div class="form-actions">
<input type="submit" class="btn btn-primary" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</div>
</form>
</div>
{% endblock content %}

Related

Invalid CSRF token when resetting password

I have a resetting password feature in my site, however, form is not working. When trying to set the password, a "Invalid CSRF token" is shown.
This my actual resetting password form:
<div class="login-form">
<form name="fos_user_resetting_form" method="post" action="{{ path('fos_user_resetting_reset', {'token': token}) }}" class="needs-validation" novalidate>
<div class="form-group">
<label for="fos_user_resetting_form_plainPassword_first" class="required">{{ 'form.password'|trans }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-key"></i></div>
<input type="password" class="form-control" id="fos_user_resetting_form_plainPassword_first" name="fos_user_resetting_form[plainPassword][first]" required="required" autocomplete="new-password" />
<div class="invalid-tooltip">Por favor, ingrese la nueva contraseña.</div>
</div>
</div>
<div class="form-group">
<label for="fos_user_resetting_form_plainPassword_second" class="required">{{ 'form.password_confirmation'|trans }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-key"></i></div>
<input type="password" class="form-control" id="fos_user_resetting_form_plainPassword_second" name="fos_user_resetting_form[plainPassword][second]" required="required" autocomplete="new-password" />
<div class="invalid-tooltip" id="confirm_password_error">Por favor, ingrese la nueva contraseña.</div>
</div>
</div>
<div>
<button type="submit" id="_submit" name="_submit" class="btn btn-success btn-flat m-b-30 m-t-30">{{ 'resetting.reset.submit'|trans }}</button>
</div>
</form>
</div>
I Know I need to add a _csrf_token hidden input to form, but, how?
I tried with
{% if csrf_token %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
{% endif %}
With:
{% if _token %}
<input type="hidden" name="_csrf_token" value="{{ _token }}" />
{% endif %}
With:
<input type="hidden" id="fos_user_resetting_form__token" name="fos_user_resetting_form[_token]" value="{{ _token }}" />
And other attempts... but none works. In all cases, twig error is shown with 'Variable "_token" does not exist.'
When using Symfony debug toolbar, I see clearly the variable is called "_token". I don't know what else to try.
EDIT: when seeing Symfony Profiler, this is shown. Variable "_token" does exist, but I don't find a way to use it in the view.
when using the default FOSUserBundle form, the value of _token is rendered. I could not find how it is actually rendered, since it uses {{ form_widget(form) }} and when I saw the corresponding Form Type, I did not see any clue about this.
Thanks
Jaime
Finally, it was easier than I thought.
I added simply {{ form_widget(form._token) }} where the token should be in the form. That way, the correct token value was rendered for the hidden input field.
Regards
Jaime
Have you tried the following? From How to Implement CSRF Protection
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
For anyone trying to add the csrf token without generating the whole form, you can use in your twig template {{ fos_csrf_provider.refreshToken('resetting') }}. Example :
<!-- Form -->
<form id="change-password-form" action="{{ path("user_resetting_reset",{'token': token}) }}" method="post" name="change-password-form">
<div class="form-group">
<input id="change_password_first_password" class="input form-control" required type="password" name="first" placeholder="{% trans %}New password{% endtrans %}">
</div>
<div class="form-group">
<input id="change_password_second_password" class="input form-control" required type="password" name="second" placeholder="{% trans %}Retype new password{% endtrans %}">
</div>
<input type="hidden" id="profile_token" name="_token" value="{{ fos_csrf_provider.refreshToken('resetting') }}" />
<button type="submit" class="btn btn-block ui-gradient-green shadow-md">Reset</button>
</form>
<!-- Form -->

FOSUserBundle Custom forms using Bootstrap

I'm using FOSUserBundle in my Symfony application. Everything work but i would like to know how to custom the render of the forms delivered by the bundle.
I have already succesfully custom the login form but i didn't find the way to custom for example the changePassword.html.twig.
I'have checked in ChangePasswordFormType.php to see if I can get the differents fields of the form but I must have missed something.
For example in my FOSUserBundle login.html.twig:
<form class="form-group-lg" action="{{ path("fos_user_security_check") }}" method="post">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<fieldset>
{% if error %}
<div class="row">
<div class="alert alert-danger" role="alert">{{ error|trans({}, 'FOSUserBundle') }}</div>
</div>
{% endif %}
<div class="row">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input class="form-control" for="username" placeholder="{{ 'security.login.username'|trans({}, 'FOSUserBundle') }}" type="text" id="username" name="_username" value="{{ last_username }}" required="required" />
</div>
</div>
<div class="row">
</div>
<br>
<div class="row">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
<input class="form-control" for="password" placeholder="{{ 'security.login.password'|trans({}, 'FOSUserBundle') }}" type="password" id="password" name="_password" required="required" />
</div>
<p class="text-right"> <a href={{ path('fos_user_resetting_request') }}> Mot de passe oublié ?</a></p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" for="remember_me"/>{{ 'security.login.remember_me'|trans({}, 'FOSUserBundle') }}
</label>
</div>
<input class="btn btn-lg btn-primary btn-block" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans({}, 'FOSUserBundle') }}" />
</fieldset>
</form>
I'm looking for using the same syntax as {{ 'security.login.username'|trans({}, 'FOSUserBundle') }} for the others template provided by FOSUserBundleto get boostrap theme on it.
If someone have already done that i would like to know how you've done this.
Thanks.
FOSUserBundle templates are located at : vendor/friendsofsymfony/user-bundle/Resources/views/
To override these templates, create the folder app/Resources/FOSUserBundle/views then, you create a template with the same name as the FOSUserBundle template you want to override.
For example to override the change passord template :
vendor/friendsofsymfony/user-bundle/Resources/views/ChangePassword/change_password.html.twig
You must create app/Resources/FOSUserBundle/views/ChangePassword/change_passord.html.twig

FOSUserBundle. Include login form in my template

Hi I'm trying to include the login form of the FOSUser Bundle in my custom template. Like that:
{% include 'FOSUserBundle:Security:login.html.twig' %}
But I have this error:
Variable "error" does not exist in FOSUserBundle:Security:login.html.twig at line 7
Is there a way to include the template without adding something in my controller?
To overriding FosUserBundle's template you have to do this :
Create a folder FOSUserBundle/view in app/Resources
Copy the view folder of FOSUserBundle in your folder you have create just before
And you can include your template and custom FOSUser view.
Example :
layout.html.twig of FOSUser in app/Resources/FOSUserBundle/view:
{% extends ":layout:Public/layout.html.twig" %} #My layout
{% block body %}
<div>
{% block fos_user_content %}
{% endblock fos_user_content %}
</div>
{% endblock %}
And app/Resources/FOSUserBundle/view/Security/login.html.twg :
{% extends "FOSUserBundle::layout.html.twig" %}
{% trans_default_domain 'FOSUserBundle' %}
{% block fos_user_content %}
<div class="col-md-4">
<form action="{{ path("fos_user_security_check") }}" method="post">
<h2 class="form-signin-heading">Se connecter </h2>
<hr>
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<label class="sr-only" for="username">{{ 'security.login.username'|trans }}</label>
<input class="form-control" type="text" id="username" name="_username" value="{{ last_username }}" required="required" />
<label class="sr-only" for="password">{{ 'security.login.password'|trans }}</label>
<input class="form-control" type="password" id="password" name="_password" required="required" placeholder="Mot de passe" />
<div class="checkbox">
<label>
<input type="checkbox" id="remember_me" name="_remember_me" value="on" />
<label for="remember_me">{{ 'security.login.remember_me'|trans }}</label>
</label>
</div>
<input class="btn btn-primary" type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans }}" />
</form>
<br>
Mot de passe perdu ?
</div>
<div class="col-md-2"></div>
<div class="col-md-3">
<h2>Pas encore inscrit ?</h2>
<hr>
<em>
nous vous invitons à vous inscrire<br />
</em>
<br /><br />
S'inscrire
</div>
{% endblock fos_user_content %}
I think there is many solutions, but according to me it's the better way to overrinding fosuser's views
This template is expected to be rendered as a full page. To include it, it might be more convenient to render the controller action.
{{ render(controller('FOSUserBundle:Security:login')) }}

Symfony Demo Application - where to find twigs?

I'm trying to orientate myself with Symfony framework by going through the "Symfony Demo application" and am trying to work my way through the interconnections. However in the below code snippet I can't find where this twig reference is getting defined value="{{ last_username }}":
\app\Resources\view\security\login.html.twig
{% extends 'base.html.twig' %}
{% block body_id 'login' %}
{% block main %}
{% if error %}
<div class="alert alert-danger">
{{ error.messageKey|trans(error.messageData) }}
</div>
{% endif %}
<div class="row">
<div class="col-sm-5">
<div class="well">
<form action="{{ path('security_login_check') }}" method="post">
<fieldset>
<legend><i class="fa fa-lock"></i> Secure Sign in</legend>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" class="form-control"/>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="_password" class="form-control" />
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"/>
<button type="submit" class="btn btn-primary">
<i class="fa fa-sign-in"></i> Sign in
</button>
</fieldset>
</form>
</div>
</div>
I have searched the whole demo application for last_username and it only appears in these four files:
\app\cache\dev\classes.php
\app\cache\prod\classes.php
\vendor\symfony\symfony\src\Symfony\Component\Security\Core\SecurityContextInterface.php
\vendor\symfony\symfony\src\Symfony\Component\Security\Core\Security.php
...all of which don't seem to offer anything helpful of defining last_username.
The last_username parameter is passed to the template via the SecurityController, which is defined in the src/AppBundle/Controller/SecurityController.php file.
One of the coolest features of the Symfony Demo application is that all pages include a Show code which shows you both the controller and the template used to create the page you are looking at. For example, in the case of the login page:

Django styling login forms and adding additional spans

I have two questions in form-styling.
For my login, I am using Django's default auth features and haven't written any views or forms manually.
urls.py
urlpatterns += patterns(
'django.contrib.auth.views',
url(r'^login/$','login',
{'template_name':'login.html'},
name='qna_login'),
url(r'^logout/$','logout',
{'next_page':'qna_home'},
name='qna_logout'),
)
login.html
{% extends "base.html" %}
{% block content%}
{% if form.errors %}
<p class="text-warning"> Your username and/or password didn't match </p>
{% endif%}
<form role="form" class="form-horizontal" method="post" action="{% url 'django.contrib.auth.views.login' %}">
<div class="form-group">
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
{% endblock %}
How do I add bootstrap styling to it?
For new user registration, I have added some bootstrap specific styles, but need to add additional spans and replace the labels with Glyphicons.
forms.py
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password')
def __init__(self, *args, **kwargs):
super(UserForm,self).__init__(*args,**kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':'Username'})
self.fields['email'].widget.attrs.update({'class':'form-control','placeholder':'Email'})
self.fields['password'].widget.attrs.update({'class':'form-control','placeholder':'Password'})
What I need to do is replace what is generated in the template, such as
<p><label for="id_username">Username:</label> <input class="form-control" id="id_username" maxlength="30" name="username" placeholder="Username" type="text" /> <span class="helptext">Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters</span></p>
by a custom bootstrap addon and glyphicon, like
<div class="input-group">
<span class="input-group-addon" style="background-color:#b77b48; color:white"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" class="form-control" placeholder="Username">
</div>
You can render each field individually instead of letting Django render the whole form with {{ form }}. You can write the template like this -
<form role="form" class="form-horizontal" method="post" action="{% url 'django.contrib.auth.views.login' %}">{% csrf_token %}
<div class="form-group">
{% for field in form %}
<div class="input-group">
<span class="input-group-addon" style="background-color:#b77b48; color:white"><span class="glyphicon glyphicon-user"></span></span>
<input class="form-control" id="{{ field.id_for_label }}" maxlength="30" name="{{ field.html_name }}" value="{{ field.value }}" type="text" />
{{ field.errors }}
</div>
{% endfor %}
<input type="submit" class="btn btn-primary" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
As always, like everything else, Django documentation has everything.

Resources