Guard: Joyful Authentication
…now bin/console server:run:
Try out /login.
To use guard, we need a new class. I'll create a new directory called Security,
but that's not important. Call the class WeirdFormAuthenticator.Next, make
this class implement GuardAuthenticatorInterface or extend the slightly easier
AbstractGuardAuthenticator:
…
EntityType Validation: Restrict Invalid programmerId
…the custom query builder. Now, if someone passes a programmer id that we
do not own, the EntityType will automatically cause a validation error. Security
is built-in.
Head back to the terminal to try it!
Awesome! Well, it failed - but look! It's just…
Adding Battle Validation
…client
from starting a battle with a Programmer that they do not own? Right now - nothing,
besides karma and trusting that humankind will do the right thing. Unfortunately,
that doesn't usually pass a security audit. Let's be heros and fix this security hole!
The "Entry Point" & Multiple Firewalls
…our start() method in this situation? So what gives?
Open up security.yml:
Here's the problem: we have a single firewall. When an anonymous request accesses
the site and hits a page that requires a valid user, Symfony has to figure out what
one…
Create a Shiny JSON Web Token
…to hide the fact that the username was wrong, you can throw
a BadCredentialsException instead - you'll see me do that in a second.
Checking the password is easy: $isValid = $this->get('security.password_encoder')
->isPasswordValid(). Pass it the $user object and the raw…
GET Your (One) Battle On
…showAction will have an $id
argument.
From here, life is really familiar. First, do we need security? - always ask
yourself that. I'm going to decide that anyone can fetch battle details out
without being authenticated. So we won't add any protection.
We will…
Creating Token Resources in the API
…put our first scenario here, which is going to be the working
scenario for creating a token. Even though a token relates to security it’s
really no different than any other resource we’re creating, like a programmer
resource. So the scenario for this…
Centralizing Error Response Creation
…src/KnpU/CodeBattle/Security/Authentication/ApiEntryPoint.php
// ...
use KnpU\CodeBattle\Api\ApiProblemResponseFactory;
class ApiEntryPoint implements AuthenticationEntryPointInterface
{
}
So now, when this object is created we’re going to have access to this
ApiProblemResponseFactory. Down below, we can just use it:
// src/KnpU/CodeBattle/Security/Authentication/ApiEntryPoint…
Authentication Error Format
…are working.
We are denying access, sending a 401, and because of our security error handling
in that ApiEntryPoint class, we’re sending a nice api problem format with
the actual detail set to “Invalid Credentials.” Like before, this message
comes from deep inside Silex…
Authorization via a Token
…
So let’s hook this up! Some of this is specific to Silex’s security system,
but in case you’re using something else, we’ll stay high level enough to see
what types of things you need to do in your system to make…
Doctrine Event Listeners
…is being saved, we’ll just ignore it. This is important because the function
is called when any entity is saved:
// src/Yoda/UserBundle/Doctrine/UserListener.php
// ...
public function prePersist(LifecycleEventArgs $args)
{
}
Injecting the security.encoder_factory Dependency¶
We’re almost done. You’ve probably…
User Serialization
…
Clearly that’s not the case: Symfony’s security system is smart enough to
take the id and query for a full fresh copy of the User object on each
request.
We can see this right in the web debug toolbar: once a user is…
Adding Dynamic Roles to each User
…exists, but it’s not actually used during login.
To make this work, change the User class to implement
AdvancedUserInterface
instead of UserInterface:
// src/Yoda/UserBundle/Entity/User.php
// ...
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
class User implements AdvancedUserInterface
{
}
Tip
For the OO geeks…
Saving Users
…strange, but stay with me. First, we ask Symfony for a
special “encoder” object that knows how to encrypt our passwords. Remember
the bcrypt config we put in security.yml? Yep, this object will use that.
After we grab the encoder, we just call encodePassword()…
Gherkin
…imagine that park security wants to
control park fences from a mobile app, while vacationing thousands of miles away.
Feature: Remote fence control API
In order to control fence security from anywhere
As an API user
I need to be able to POST JSON instructions…
Custom Authenticator authenticate() Method
…new Passport().
By the way, if you're new to the custom authenticator system and want to learn
more, check out our Symfony 5 Security tutorial
where we talk all about this. I'll go through the basics now, but the details
live there.
Before…
Hunting Down the Final Deprecations
…the list says:
SessionInterface aliases are deprecated, use $requestStack->getSession()
instead. It's being referenced by the LoginFormAuthenticator service.
Let's go check that out! Open src/Security/LoginFormAuthenticator.php. Ahh.
I'm autowiring the SessionInterface service. In Symfony 6, that service no
longer exists…
Prod Vault Optimization & Vault for Tests
…values and the private key to decrypt them. Storing the secrets in
plain text but removing the decrypt key from production is really the same thing
from a security standpoint.
The point is: there's no security difference. Let's delete the .env.prod.local…
Overriding Secrets Locally (Local Vault)
…MAILER_DSN secret... but add an
extra --local flag to the end:
So far... this looks identical to before. I'll paste in my Mailtrap value... which
the command hides for security reasons. And... fascinating! This didn't change
our dev vault at all! Nope…
Updating the webpack-encore-bundle Recipe
…out, it's super minor:
It disables a validator in the test environment that makes a network request
and is a security-related feature that just isn't needed in your tests.
The last new file is in the same directory - webpack_encore.yaml:
Which..…
x
1000+